Compartilhar via


Substituições de amostragem (versão prévia) – Azure Monitor Application Insights para Java

Observação

O recurso de substituição de amostragem está no GA, a partir da versão 3.5.0.

As substituições de amostragem permitem que você substitua a porcentagem de amostragem padrão, por exemplo:

  • Defina o percentual de amostragem como 0 (ou algum valor pequeno) para verificações de integridade com ruídos.
  • Defina o percentual de amostragem como 0 (ou algum valor pequeno) para chamadas de dependência com ruídos.
  • Defina o percentual de amostragem como 100 para um tipo de solicitação importante (por exemplo, /login), mesmo que você tenha a amostragem padrão configurada com um valor menor.

Terminologia

Antes de aprender sobre as substituições de amostragem, você deve entender o termo span. Span é um termo geral para:

  • Uma solicitação de entrada.
  • Uma dependência de saída (por exemplo, uma chamada remota para outro serviço).
  • Uma dependência em processo (por exemplo, trabalho sendo feito por subcomponentes do serviço).

Para substituições de amostragem, esses componentes de span são importantes:

  • Atributos

Atributos de span representam propriedades padrão e personalizadas de uma determinada solicitação ou dependência.

Introdução

Para começar, crie um arquivo de configuração chamado applicationinsights.jsem. Salve-o no mesmo diretório que applicationinsights-agent-*.jar. Use o modelo a seguir.

{
  "connectionString": "...",
  "sampling": {
    "percentage": 10,
    "overrides": [
      {
        "telemetryType": "request",
        "attributes": [
          ...
        ],
        "percentage": 0
      },
      {
        "telemetryType": "request",
        "attributes": [
          ...
        ],
        "percentage": 100
      }
    ]
  }
}

Como ele funciona

telemetryType (telemetryKind no Application Insights 3.4.0) deve ser um de request, dependency, trace (log) ou exception.

Quando um span é iniciado, o tipo de span e os atributos presentes são usados para verificar se há correspondência de alguma das substituições de amostragem.

As correspondências podem ser strict ou regexp. Correspondências de expressão regular são executadas com base no valor do atributo inteiro, portanto, se você quiser corresponder a um valor que contenha abc em qualquer lugar, use .*abc.*. Uma substituição de amostragem pode especificar vários critérios de atributo, nesse caso, todos eles precisam corresponder para que a substituição de amostragem corresponda.

Se houver correspondência de uma das substituições de amostragem, o percentual de amostragem será usado para decidir se o span deve ser amostrado ou não.

Somente a primeira substituição de amostragem que corresponde é usada.

Se nenhuma substituição de amostragem corresponder:

Atributos de span disponíveis para amostragem

Os atributos de intervalo do OpenTelemetry são coletados automaticamente e baseados nas convenções semânticas do OpenTelemetry.

Você também pode adicionar programaticamente atributos de intervalo e usá-los para amostragem.

Observação

Para ver o conjunto exato de atributos capturados pelo Java do Application Insights para seu aplicativo, defina o nível de autodiagnóstico como depuração e procure mensagens de depuração que comecem com o texto "exportando span".

Observação

Somente os atributos definidos no início do intervalo estão disponíveis para amostragem. Portanto, atributos como http.response.status_code ou duração da solicitação, que são capturados posteriormente, podem ser filtrados através das extensões Java OpenTelemetry. Aqui está uma extensão de exemplo que filtra intervalos com base na duração da solicitação.

Observação

Os atributos adicionados com um processador de telemetria não estão disponíveis para amostragem.

Casos de uso

Suprimir a coleta de telemetria para verificações de integridade

Esse exemplo suprime a coleta de telemetria para todas as solicitações de /health-checks.

Esse exemplo também suprime a coleta de todos os spans downstream (dependências) que normalmente seriam coletados como /health-checks.

{
  "connectionString": "...",
  "sampling": {
    "overrides": [
      {
        "telemetryType": "request",
        "attributes": [
          {
            "key": "url.path",
            "value": "/health-check",
            "matchType": "strict"
          }
        ],
        "percentage": 0
      }
    ]
  }
}

Suprimir a coleta de telemetria para uma chamada de dependência ruidosa

Esse exemplo suprime a coleta de telemetria para todas as chamadas GET my-noisy-key do Redis.

{
  "connectionString": "...",
  "sampling": {
    "overrides": [
      {
        "telemetryType": "dependency",
        "attributes": [
          {
            "key": "db.system",
            "value": "redis",
            "matchType": "strict"
          },
          {
            "key": "db.statement",
            "value": "GET my-noisy-key",
            "matchType": "strict"
          }
        ],
        "percentage": 0
      }
    ]
  }
}

Coletar 100% da telemetria para um tipo de solicitação importante

Esse exemplo coleta 100% de telemetria para o /login.

Como os spans downstream (dependências) respeitam a decisão de amostragem do pai (na ausência de qualquer substituição de amostragem para esse span downstream), eles também serão coletados para todas as solicitações "/login".

{
  "connectionString": "...",
  "sampling": {
    "percentage": 10
  },
  "sampling": {
    "overrides": [
      {
        "telemetryType": "request",
        "attributes": [
          {
            "key": "url.path",
            "value": "/login",
            "matchType": "strict"
          }
        ],
        "percentage": 100
      }
    ]
  }
}

Expor atributos de intervalo para suprimir chamadas de dependência do SQL

Este exemplo explica a experiência de localizar atributos disponíveis para suprimir chamadas SQL com ruído. A consulta abaixo ilustra as diferentes chamadas SQL e contagens de registros associados nos últimos 30 dias:

dependencies
| where timestamp > ago(30d)
| where name == 'SQL: DB Query'
| summarize count() by name, operation_Name, data
| sort by count_ desc
SQL: DB Query    POST /Order             DECLARE @MyVar varbinary(20); SET @MyVar = CONVERT(VARBINARY(20), 'Hello World');SET CONTEXT_INFO @MyVar;    36712549    
SQL: DB Query    POST /Receipt           DECLARE @MyVar varbinary(20); SET @MyVar = CONVERT(VARBINARY(20), 'Hello World');SET CONTEXT_INFO @MyVar;    2220248    
SQL: DB Query    POST /CheckOutForm      DECLARE @MyVar varbinary(20); SET @MyVar = CONVERT(VARBINARY(20), 'Hello World');SET CONTEXT_INFO @MyVar;    554074    
SQL: DB Query    GET /ClientInfo         DECLARE @MyVar varbinary(20); SET @MyVar = CONVERT(VARBINARY(20), 'Hello World');SET CONTEXT_INFO @MyVar;    37064

Nos resultados acima, pode-se observar que todas as operações compartilham o mesmo valor no campo data: DECLARE @MyVar varbinary(20); SET @MyVar = CONVERT(VARBINARY(20), 'Hello World');SET CONTEXT_INFO @MyVar;. A convergência entre todos esses registros torna-se um bom candidato para uma substituição de amostragem.

Ao definir o autodiagnóstico para depuração, as seguintes entradas de log ficarão visíveis na saída:

2023-10-26 15:48:25.407-04:00 DEBUG c.m.a.a.i.exporter.AgentSpanExporter - exporting span: SpanData{spanContext=ImmutableSpanContext...

A área de interesse desses logs é a seção "atributos":

{
  "attributes": {
    "data": {
      "thread.name": "DefaultDatabaseBroadcastTransport: MessageReader thread",
      "thread.id": 96,
      "db.connection_string": "apache:",
      "db.statement": "DECLARE @MyVar varbinary(20); SET @MyVar = CONVERT(VARBINARY(20), 'Hello World');SET CONTEXT_INFO @MyVar;",
      "db.system": "other_sql",
      "applicationinsights.internal.item_count": 1
    }
  }
}

Usando essa saída, você pode configurar uma substituição de amostragem semelhante à mostrada abaixo que filtrará nossas chamadas SQL com ruído:

{
  "connectionString": "...",
  "preview": {
    "sampling": {
      "overrides": [
        {
          "telemetryType": "dependency",
          "attributes": [
            {
              "key": "db.statement",
              "value": "DECLARE @MyVar varbinary(20); SET @MyVar = CONVERT(VARBINARY(20), 'Hello World');SET CONTEXT_INFO @MyVar;",
              "matchType": "strict"
            }
          ],
          "percentage": 0
        }
      ]
    }
  }
}

Depois que as alterações são aplicadas, a seguinte consulta nos permite determinar a última vez que essas dependências foram ingeridas no Application Insights:

dependencies
| where timestamp > ago(30d)
| where data contains 'DECLARE @MyVar'
| summarize max(timestamp) by data
| sort by max_timestamp desc
DECLARE @MyVar varbinary(20); SET @MyVar = CONVERT(VARBINARY(20), 'Hello World');SET CONTEXT_INFO @MyVar;    11/13/2023 8:52:41 PM 

Suprimir a coleta de telemetria para log

Com o SL4J, você pode adicionar atributos de log:

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.MDC;

public class MdcClass {

  private static final Logger logger = LoggerFactory.getLogger(MdcClass.class);

  void method {
	
    MDC.put("key", "value");
    try {
       logger.info(...); // Application log to remove
    finally {
       MDC.remove("key"); // In a finally block in case an exception happens with logger.info
    }
	
  }
  
}

Você pode então remover o log com o atributo adicionado:

{
  "sampling": {
    "overrides": [
      {
        "telemetryType": "trace",
        "percentage": 0,
        "attributes": [
          {
            "key": "key",
            "value": "value",
            "matchType": "strict"
          }
        ]
      }
    ]
  }
}

Suprimir a coleta de telemetria para um método Java

Vamos adicionar um intervalo a um método Java e remover esse intervalo com a substituição de amostragem.

Primeiro, adicione a dependência opentelemetry-instrumentation-annotations:

    <dependency>
      <groupId>io.opentelemetry.instrumentation</groupId>
      <artifactId>opentelemetry-instrumentation-annotations</artifactId>
    </dependency>

Agora podemos adicionar a WithSpan anotação a um método Java que executa solicitações SQL:

package org.springframework.samples.petclinic.vet;

@Controller
class VetController {

	private final VetRepository vetRepository;

	public VetController(VetRepository vetRepository) {
		this.vetRepository = vetRepository;
	}

	@GetMapping("/vets.html")
	public String showVetList(@RequestParam(defaultValue = "1") int page, Model model) {
		Vets vets = new Vets();
		Page<Vet> paginated = findPaginated(page);
		vets.getVetList().addAll(paginated.toList());
		return addPaginationModel(page, paginated, model);
	}

	@WithSpan
	private Page<Vet> findPaginated(int page) {
		int pageSize = 5;
		Pageable pageable = PageRequest.of(page - 1, pageSize);
		return vetRepository.findAll(pageable);  // Execution of SQL requests
	}

A configuração de substituição de amostragem a seguir permite remover o intervalo adicionado pela anotação WithSpan:

  "sampling": {
    "overrides": [
      {
        "telemetryType": "dependency",
        "attributes": [
          {
            "key": "code.function",
            "value": "findPaginated",
            "matchType": "strict"
          }
        ],
        "percentage": 0
      }
    ]
  }

O valor do atributo é o nome do método Java.

Essa configuração removerá todos os dados de telemetria criados a partir do método findPaginated. As dependências do SQL não serão criadas para as execuções SQL provenientes do método findPaginated.

A configuração a seguir removerá todos os dados de telemetria emitidos por métodos da classe VetController com a anotação WithSpan:

 "sampling": {
    "overrides": [
      {
        "telemetryType": "dependency",
        "attributes": [
          {
            "key": "code.namespace",
            "value": "org.springframework.samples.petclinic.vet.VetController",
            "matchType": "strict"
          }
        ],
        "percentage": 0
      }
    ]
  }

Solução de problemas

Se você usar regexp e a substituição de amostragem não funcionar, tente com a expressão regular .*. Se a amostragem funcionar agora, isso significa que você tem um problema com a primeira expressão regular e deve ler essa documentação sobre expressões regulares.

Se isso não funcionar com .*, você poderá ter um problema de sintaxe em seu application-insights.json file. Examine os logs do Application Insights e veja se existem mensagens de aviso.