modulo 09 / lezione 49
Performance, memoria e osservabilità
Log strutturati, metriche, trace, SLO
Costruire segnali utili in produzione senza esporre dati sensibili. Introdurre SLI, SLO ed error budget.
In parole semplici
In produzione non hai DevTools. Hai solo i segnali che hai progettato in anticipo: log strutturati, metriche, trace. Senza, ogni incidente è cieco. Con, si indaga in pochi minuti.
Le SLO (Service Level Objectives) trasformano queste metriche in accordi misurabili sulla qualità del servizio.
Parole nuove
- log strutturato: log in formato chiave-valore (JSON), non testo libero.
- metrica: misura numerica nel tempo (counter, gauge, histogram).
- trace: percorso completo di una richiesta attraverso più servizi.
- correlation id: id che lega log, metriche e trace di una stessa richiesta.
- SLI / SLO / error budget: indicatori, obiettivi, margine di tolleranza.
Cosa impari
- Scrivere log strutturati in JSON.
- Tipi di metriche e loro uso (RED, USE).
- Tracciare una richiesta end-to-end.
- Definire SLO ed error budget.
Log strutturati
Anti-pattern:
console.log("Utente " + userId + " ha pagato " + importo + " in " + duration + "ms");
Difficile da:
- Filtrare.
- Aggregare.
- Cercare per campo.
Pattern strutturato:
logger.info({
event: "pagamento_completato",
user_id: userId,
importo,
duration_ms: duration,
correlation_id: correlationId,
});
Output JSON:
{"level":"info","timestamp":"2025-05-16T14:30:00Z","event":"pagamento_completato","user_id":42,"importo":99.9,"duration_ms":234,"correlation_id":"abc-123"}
Sistemi di logging (Datadog, Loki, CloudWatch) parsano JSON e permettono query:
event="pagamento_completato" AND duration_ms > 1000
Librerie: pino (Node), winston (Node), structlog (Python), Logback+ Logstash encoder (Java).
Cosa NON loggare
Mai:
- Password, token, chiavi API.
- Numeri di carta di credito completi (PCI DSS).
- Dati personali sensibili senza esplicita ragione (GDPR).
Pattern: maschera al confine.
function maskCard(num) {
return "****" + num.slice(-4);
}
logger.info({ event: "pagamento", card: maskCard(card) });
Livelli
debug → dettaglio per dev
info → eventi normali
warn → situazione strana
error → errore gestito
fatal → errore catastrofico (terminazione)
In produzione di solito info+. In dev debug+.
Metriche: tre tipi
Counter
Aumenta monotonicamente. “Quante chiamate ha ricevuto l’endpoint X?”
metrics.counter("http_requests_total", { endpoint: "/utenti", status: 200 }).inc();
Gauge
Valore corrente che sale e scende. “Quante connessioni DB attive?”
metrics.gauge("db_connections_active").set(currentValue);
Histogram
Distribuzione di valori (latenza, dimensione payload).
metrics.histogram("http_request_duration_seconds", { endpoint: "/utenti" }).observe(0.234);
Permette di calcolare p50, p95, p99.
Pattern RED e USE
RED (per servizi)
- Rate: richieste/secondo.
- Errors: errori/secondo.
- Duration: distribuzione del tempo di risposta.
USE (per risorse: CPU, RAM, disco)
- Utilization: % usato.
- Saturation: coda di lavoro pendente.
- Errors: errori.
Coprire entrambi dà visibilità completa.
Trace distribuiti
Una richiesta che attraversa 5 servizi è difficile da debuggare con log isolati. Il trace la racconta come un albero:
[gateway 250ms]
└── [auth-service 30ms]
└── [users-service 180ms]
└── [postgres 150ms]
└── [SELECT utenti WHERE id=42]
Standard: OpenTelemetry. Strumenti: Jaeger, Zipkin, Honeycomb, Datadog APM.
In codice:
import { trace } from "@opentelemetry/api";
const tracer = trace.getTracer("users-service");
const span = tracer.startSpan("fetch-user");
try {
// operazione
span.setAttribute("user.id", id);
} finally {
span.end();
}
I trace e i log si correlano via correlation id (anche detto trace id).
Correlation id
Ogni richiesta riceve un id univoco (header X-Request-ID o traceparent). Propagato in:
- Log.
- Trace.
- Errori (Sentry).
Diagnosi: ho un errore in Sentry → copio trace_id → query in Loki → vedo tutti i log di quella richiesta in tutti i servizi.
SLI, SLO, error budget
SLI (Service Level Indicator)
Misura concreta. Esempio: ”% di richieste in < 500ms”.
SLO (Service Level Objective)
Target dell’SLI. Esempio: “99% delle richieste < 500ms in 30 giorni”.
Error budget
Margine di errore tollerato. Se SLO = 99.9% disponibilità, error budget = 0.1% = ~43 minuti/mese di downtime.
Usato per decidere:
- Se il budget è consumato, si stoppa il rilascio di feature nuove e si lavora su stabilità.
- Se il budget è avanzato, si può rischiare di più.
Trasforma decisioni “sentite” in decisioni “numerate”.
Esercizio guidato
In un piccolo server:
- Sostituisci
console.logconpinoin JSON. - Aggiungi un middleware che genera un correlation id e lo mette in ogni log della richiesta.
- Aggiungi un counter per richieste e un histogram per latenza (usa
prom-client). - Espone
/metricsin formato Prometheus. - Definisci uno SLO: “p95 < 200ms” e verificalo nei tuoi dati.
Errori frequenti del principiante
- Log testuali in produzione. Impossibili da aggregare.
- Log con dati sensibili. Compliance violata, multe.
- Metriche senza histogram. Vedi la media ma non i p95/p99.
- SLO senza error budget. Hai un numero, non una decisione.