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:
- Se si tratta del primo intervallo nella traccia, viene usata la configurazione di campionamento di primo livello.
- Se non è il primo intervallo nella traccia, viene usata la decisione di campionamento padre.
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.