Condividi tramite


Override di campionamento - Monitoraggio di Azure di Application Insights per Java

Nota

La funzionalità di override del campionamento è disponibile a livello generale, a partire dalla versione 3.5.0.

Gli override di campionamento consentono di eseguire l'override della percentuale di campionamento predefinita, ad esempio:

  • Impostare la percentuale di campionamento su 0 (o su un valore ridotto) per i controlli di integrità eccessivi.
  • Impostare la percentuale di campionamento su 0 (o su un valore ridotto) per le chiamate di dipendenza eccessive.
  • Impostare la percentuale di campionamento su 100 per un tipo di richiesta importante, ad esempio /login, anche se il campionamento predefinito è configurato su un valore inferiore.

Terminologia

Prima di conoscere le sostituzioni di campionamento, è necessario comprendere il termine span. Uno span è un termine generale per:

  • Una richiesta in ingresso.
  • Dipendenza in uscita, ad esempio una chiamata remota a un altro servizio.
  • Dipendenza in-process (ad esempio, il lavoro svolto dai sottocomponenti del servizio).

Per gli override del campionamento, questi componenti span sono importanti:

  • Attributi

Gli attributi span rappresentano proprietà standard e personalizzate di una determinata richiesta o dipendenza.

Introduzione

Per iniziare, creare un file di configurazione denominato applicationinsights.json. Salvarlo nella stessa directory di applicationinsights-agent-*.jar. Usare il modello seguente.

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

Funzionamento

telemetryType (telemetryKind in Application Insights 3.4.0) deve essere uno tra request, dependency, trace (log) o exception.

Quando viene avviato un intervallo, il tipo di intervallo e gli attributi presenti in tale intervallo vengono usati per verificare se una delle sostituzioni di campionamento corrisponde.

Le corrispondenze possono essere strict o regexp. Le corrispondenze dell'espressione regolare vengono eseguite sull'intero valore dell'attributo, quindi se si vuole trovare una corrispondenza con un valore che contiene abc in un punto qualsiasi, è necessario usare .*abc.*. Un override di campionamento può specificare più criteri di attributo, nel qual caso tutti devono corrispondere per la corrispondenza dell'override di campionamento.

Se una delle sostituzioni di campionamento corrisponde, viene usata la percentuale di campionamento per decidere se campionare o meno l'intervallo.

Viene usato solo il primo override di campionamento corrispondente.

Se nessuna sostituzione di campionamento corrisponde:

Attributi span disponibili per il campionamento

Gli attributi di intervallo OpenTelemetry vengono raccolti automaticamente e basati sulle convenzioni semantiche OpenTelemetry.

È anche possibile aggiungere attributi span a livello di codice e usarli per il campionamento.

Nota

Per visualizzare il set esatto di attributi acquisiti da Application Insights Java per l'applicazione, impostare il livello di auto-diagnostica su debug e cercare i messaggi di debug a partire dal testo "Intervallo di esportazione".

Nota

Solo gli attributi impostati all'inizio dell'intervallo sono disponibili per il campionamento, quindi gli attributi come http.response.status_code o la durata della richiesta acquisiti in un secondo momento possono essere filtrati tramite le estensioni Java OpenTelemetry. Ecco un'estensione di esempio che filtra in base alla durata della richiesta.

Nota

Gli attributi aggiunti con un processore di telemetria non sono disponibili per il campionamento.

Casi d'uso

Eliminare la raccolta dei dati di telemetria per i controlli di integrità

In questo esempio viene eliminata la raccolta dei dati di telemetria per tutte le richieste a /health-checks.

In questo esempio viene inoltre eliminata la raccolta di intervalli downstream (dipendenze) normalmente raccolti in /health-checks.

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

Eliminare la raccolta dei dati di telemetria per una chiamata di dipendenza rumorosa

In questo esempio viene eliminata la raccolta dei dati di telemetria per tutte le chiamate redis GET my-noisy-key.

{
  "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
      }
    ]
  }
}

Raccogliere il 100% dei dati di telemetria per un tipo di richiesta importante

Questo esempio raccoglie il 100% dei dati di telemetria per /login.

Poiché gli intervalli downstream (dipendenze) rispettano la decisione di campionamento dell'elemento padre (assente qualsiasi override di campionamento per tale intervallo downstream), vengono raccolti anche per tutte le richieste '/login'.

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

Esposizione di attributi di intervallo per eliminare le chiamate alle dipendenze SQL

In questo esempio viene illustrata l'esperienza di ricerca degli attributi disponibili per eliminare le chiamate SQL rumorose. La query seguente illustra le diverse chiamate SQL e i conteggi dei record associati negli ultimi 30 giorni:

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

Dai risultati precedenti, è possibile osservare che tutte le operazioni condividono lo stesso valore nel data campo : DECLARE @MyVar varbinary(20); SET @MyVar = CONVERT(VARBINARY(20), 'Hello World');SET CONTEXT_INFO @MyVar;. La comunità tra tutti questi record lo rende un buon candidato per un override di campionamento.

Impostando la diagnostica automatica su come eseguire il debug, le voci di log seguenti diventeranno visibili nell'output:

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

L'area di interesse di tali log è la sezione "attributi":

{
  "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 tale output, è possibile configurare un override di campionamento simile a quello riportato di seguito che filtra le chiamate SQL rumorose:

{
  "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
        }
      ]
    }
  }
}

Dopo l'applicazione delle modifiche, la query seguente consente di determinare l'ultima volta che queste dipendenze sono state inserite in 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 

Eliminare la raccolta dei dati di telemetria per il log

Con SL4J è possibile aggiungere attributi di 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
    }
	
  }
  
}

È quindi possibile rimuovere il log con l'attributo aggiunto:

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

Eliminare la raccolta dei dati di telemetria per un metodo Java

Verrà aggiunto un intervallo a un metodo Java e verrà rimosso questo intervallo con override del campionamento.

Aggiungere prima di tutto la opentelemetry-instrumentation-annotations dipendenza:

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

È ora possibile aggiungere l'annotazione WithSpan a un metodo Java che esegue richieste 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
	}

La configurazione dell'override del campionamento seguente consente di rimuovere l'intervallo aggiunto dall'annotazione WithSpan :

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

Il valore dell'attributo è il nome del metodo Java.

Questa configurazione rimuoverà tutti i dati di telemetria creati dal findPaginated metodo . Le dipendenze SQL non verranno create per le esecuzioni SQL provenienti dal findPaginated metodo .

La configurazione seguente rimuoverà tutti i dati di telemetria generati dai metodi della VetController classe con l'annotazione WithSpan :

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

Risoluzione dei problemi

Se si usa regexp e l'override di campionamento non funziona, provare con l'espressione regolare .*. Se il campionamento funziona ora, significa che si è verificato un problema con la prima espressione regolare e leggere questa documentazione dell’espressione regolare.

Se non funziona con .*, è possibile che si verifichi un problema di sintassi in application-insights.json file. Esaminare i log di Application Insights e verificare se si notano dei messaggi di avviso.