OpenTelemetry: Lo Standard per la Telemetria Moderna
OpenTelemetry (OTel) e un framework open source, vendor-neutral, per la generazione, raccolta e esportazione di dati di telemetria. Nato dalla fusione di due progetti precedenti (OpenTracing e OpenCensus), OTel e oggi il secondo progetto più attivo della Cloud Native Computing Foundation (CNCF) dopo Kubernetes, con oltre 1.000 contributori e il supporto di tutti i principali vendor di observability.
OTel non e un backend di observability: non archivia dati e non fornisce dashboard. E uno standard di instrumentazione che definisce come raccogliere metriche, log e tracce dal codice applicativo e inviarli a qualsiasi backend compatibile (Jaeger, Prometheus, Datadog, New Relic, Grafana Cloud e molti altri).
Questo approccio vendor-neutral risolve un problema critico: instrumenti il tuo codice una sola volta con le API OTel, e puoi cambiare backend di observability senza toccare una riga di codice applicativo.
Cosa Imparerai in Questo Articolo
- L'architettura di OpenTelemetry: API, SDK, Collector e OTLP
- La distinzione fondamentale tra API e SDK
- I tre segnali OTel: Traces, Metrics e Logs
- Le Semantic Conventions e perchè sono importanti
- Il protocollo OTLP (OpenTelemetry Protocol)
- La maturity matrix e lo stato di ogni componente
Architettura di OpenTelemetry
L'architettura OTel e composta da quattro componenti principali che collaborano per fornire un pipeline di telemetria completo, dall'instrumentazione del codice fino all'esportazione verso i backend di storage e visualizzazione.
1. API: Il Contratto di Instrumentazione
L'API e il layer di astrazione che il codice applicativo utilizza per generare telemetria. Definisce interfacce e tipi senza implementazione concreta. Se installi solo l'API senza un SDK, tutte le chiamate diventano no-op (operazioni vuote), garantendo zero overhead in ambienti dove la telemetria non e necessaria.
Questa separazione e fondamentale per le librerie: una libreria instrumentata con l'API OTel non forza l'applicazione che la usa ad adottare un SDK specifico. L'applicazione decide se e come raccogliere la telemetria registrando un SDK.
2. SDK: L'Implementazione Concreta
L'SDK implementa le interfacce dell'API con logica concreta di raccolta, processing e esportazione. L'SDK gestisce:
- Sampling: decidere quali tracce raccogliere e quali scartare
- Batching: raggruppare i dati di telemetria per invii efficienti
- Resource detection: identificare automaticamente l'ambiente (host, container, cloud)
- Export: inviare i dati al backend tramite gli Exporters configurati
# Setup completo dell'SDK OpenTelemetry in Python
from opentelemetry import trace, metrics
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.export import BatchSpanProcessor
from opentelemetry.sdk.metrics import MeterProvider
from opentelemetry.sdk.metrics.export import PeriodicExportingMetricReader
from opentelemetry.sdk.resources import Resource
from opentelemetry.exporter.otlp.proto.grpc.trace_exporter import OTLPSpanExporter
from opentelemetry.exporter.otlp.proto.grpc.metric_exporter import OTLPMetricExporter
# 1. Definire la Resource (identità del servizio)
resource = Resource.create({
"service.name": "order-service",
"service.version": "1.2.0",
"deployment.environment": "production",
"service.instance.id": "order-service-pod-abc123"
})
# 2. Configurare il TracerProvider con exporter OTLP
tracer_provider = TracerProvider(resource=resource)
otlp_trace_exporter = OTLPSpanExporter(
endpoint="http://otel-collector:4317",
insecure=True
)
tracer_provider.add_span_processor(
BatchSpanProcessor(otlp_trace_exporter)
)
trace.set_tracer_provider(tracer_provider)
# 3. Configurare il MeterProvider con exporter OTLP
otlp_metric_exporter = OTLPMetricExporter(
endpoint="http://otel-collector:4317",
insecure=True
)
metric_reader = PeriodicExportingMetricReader(
otlp_metric_exporter,
export_interval_millis=60000
)
meter_provider = MeterProvider(
resource=resource,
metric_readers=[metric_reader]
)
metrics.set_meter_provider(meter_provider)
3. Collector: Il Router di Telemetria
L'OTel Collector e un componente standalone che riceve, processa e esporta dati di telemetria. Funziona come un proxy intelligente tra le applicazioni e i backend, offrendo funzionalità di batching, retry, filtering e trasformazione dei dati.
Il Collector e opzionale: le applicazioni possono esportare direttamente ai backend. Tuttavia, il Collector e fortemente raccomandato in produzione per disaccoppiare le applicazioni dalla configurazione dei backend e centralizzare la gestione della telemetria.
4. OTLP: Il Protocollo di Trasporto
L'OTLP (OpenTelemetry Protocol) e il protocollo nativo per il trasporto di telemetria in OTel. Supporta tre modalità di trasporto: gRPC (default, alta performance), HTTP/protobuf (compatibilità firewall) e HTTP/JSON (debug e testing). Tutti e tre trasportano gli stessi dati con encoding diversi.
Architettura OTel: Flusso dei Dati
Applicazione (API + SDK) → Exporter (OTLP) → Collector (Receivers → Processors → Exporters) → Backend (Jaeger, Prometheus, Grafana Cloud, ecc.)
I Tre Segnali di OpenTelemetry
OTel supporta i tre tipi di segnali di telemetria, ognuno a un diverso livello di maturita:
Traces (Stable)
Il segnale più maturo di OTel. Le tracce distribuite rappresentano il percorso di una richiesta attraverso i servizi, composte da span con attributi, eventi e link. L'API di tracing e stabile in tutti i linguaggi principali.
Metrics (Stable)
Le metriche OTel supportano tre tipi di strumenti: Counter, Histogram e Gauge. L'API delle metriche e stabile e supporta aggregazioni configurabili, temporalita (cumulative e delta) e cardinalita controllata tramite Views.
Logs (Stable)
A differenza di tracce e metriche, OTel non introduce un nuovo API per il logging. Invece, fornisce un Log Bridge API che connette i framework di logging esistenti (Log4j, SLF4J, Python logging, Winston) al pipeline OTel, arricchendo i log con trace context automaticamente.
Maturity Matrix dei Segnali OTel
| Segnale | API | SDK | OTLP | Auto-Instrumentation |
|---|---|---|---|---|
| Traces | Stable | Stable | Stable | Stable (Java, Python, .NET) |
| Metrics | Stable | Stable | Stable | Stable (Java, .NET) |
| Logs | Stable | Stable | Stable | Stable (Java) |
Semantic Conventions: Il Vocabolario Condiviso
Le Semantic Conventions sono un insieme standardizzato di nomi per attributi, metriche e span che garantiscono interoperabilità tra librerie, framework e backend diversi. Senza convenzioni semantiche, ogni team userebbe nomi diversi per gli stessi concetti, rendendo impossibile la correlazione e l'analisi cross-service.
# Esempi di Semantic Conventions per HTTP
# Tutte le librerie HTTP usano gli stessi nomi di attributi
# Attributi per span HTTP server
span.set_attribute("http.request.method", "POST")
span.set_attribute("url.path", "/api/v1/orders")
span.set_attribute("http.response.status_code", 201)
span.set_attribute("server.address", "api.example.com")
span.set_attribute("server.port", 443)
span.set_attribute("network.protocol.version", "1.1")
span.set_attribute("http.route", "/api/v1/orders")
# Attributi per span Database
span.set_attribute("db.system", "postgresql")
span.set_attribute("db.namespace", "orders_db")
span.set_attribute("db.operation.name", "SELECT")
span.set_attribute("db.query.text", "SELECT * FROM orders WHERE id = ?")
span.set_attribute("server.address", "db.internal")
span.set_attribute("server.port", 5432)
# Attributi per span Messaging
span.set_attribute("messaging.system", "kafka")
span.set_attribute("messaging.destination.name", "order-events")
span.set_attribute("messaging.operation.type", "publish")
span.set_attribute("messaging.message.id", "msg-12345")
Le Semantic Conventions coprono domini come HTTP, database, messaging, RPC, cloud providers, container runtime e molti altri. Seguirle garantisce che i backend possano interpretare correttamente la telemetria e fornire dashboard e analisi preconfigurate.
SDK per Linguaggi: Ecosistema Multi-Language
OTel fornisce SDK ufficiali per i principali linguaggi di programmazione. Ogni SDK implementa le stesse API con idiomi specifici del linguaggio, garantendo un'esperienza nativa:
// Setup OTel SDK in Java con Spring Boot
// build.gradle.kts
// implementation("io.opentelemetry:opentelemetry-api:1.36.0")
// implementation("io.opentelemetry:opentelemetry-sdk:1.36.0")
// implementation("io.opentelemetry:opentelemetry-exporter-otlp:1.36.0")
import io.opentelemetry.api.OpenTelemetry;
import io.opentelemetry.api.trace.Tracer;
import io.opentelemetry.api.trace.Span;
import io.opentelemetry.api.metrics.Meter;
import io.opentelemetry.api.metrics.LongCounter;
import io.opentelemetry.context.Scope;
public class OrderService {
private final Tracer tracer;
private final LongCounter orderCounter;
public OrderService(OpenTelemetry openTelemetry) {
this.tracer = openTelemetry.getTracer("order-service", "1.0.0");
Meter meter = openTelemetry.getMeter("order-service", "1.0.0");
this.orderCounter = meter.counterBuilder("orders.created")
.setDescription("Number of orders created")
.setUnit("1")
.build();
}
public Order createOrder(OrderRequest request) {
Span span = tracer.spanBuilder("create-order")
.setAttribute("order.type", request.getType())
.setAttribute("order.items_count", request.getItems().size())
.startSpan();
try (Scope scope = span.makeCurrent()) {
Order order = processOrder(request);
orderCounter.add(1);
span.setAttribute("order.id", order.getId());
return order;
} catch (Exception e) {
span.recordException(e);
span.setStatus(StatusCode.ERROR, e.getMessage());
throw e;
} finally {
span.end();
}
}
}
SDK Supportati Ufficialmente
- Java: SDK maturo con auto-instrumentation agent (il più completo)
- Python: SDK stabile, auto-instrumentation per Django, Flask, FastAPI
- Go: SDK stabile, design idiomatico con context propagation nativa
- .NET: SDK stabile, integrazione profonda con ASP.NET Core
- JavaScript/Node.js: SDK stabile, auto-instrumentation per Express, Fastify
- Rust: SDK in fase di maturazione, community attiva
- C++: SDK stabile, usato in scenari ad alte prestazioni
- Swift: SDK emergente, per applicazioni iOS e macOS
Resource: L'Identita del Servizio
La Resource e un insieme di attributi che identificano l'entità che produce telemetria. E condivisa da tutti i segnali (tracce, metriche, log) e fornisce il contesto ambientale necessario per correlare i dati. La Resource viene impostata una volta all'avvio dell'SDK e rimane costante per l'intera durata del processo.
# Resource attributes tipici in un ambiente Kubernetes
resource:
attributes:
# Identita del servizio
service.name: "order-service"
service.version: "2.1.0"
service.namespace: "ecommerce"
service.instance.id: "order-service-7d8f9b-xk2mp"
# Ambiente di deployment
deployment.environment: "production"
deployment.region: "eu-west-1"
# Kubernetes metadata
k8s.namespace.name: "ecommerce-prod"
k8s.pod.name: "order-service-7d8f9b-xk2mp"
k8s.deployment.name: "order-service"
k8s.node.name: "worker-node-03"
# Cloud provider
cloud.provider: "aws"
cloud.region: "eu-west-1"
cloud.availability_zone: "eu-west-1a"
Roadmap di Adozione: Da Zero a Production
Adottare OpenTelemetry in un'organizzazione e un processo incrementale. Non serve instrumentare tutto il codice dal giorno uno. Una roadmap realistica prevede tre fasi:
Roadmap di Adozione OTel
Fase 1 (Settimana 1-2): Deploy del Collector, auto-instrumentation sui servizi principali,
configurazione del backend (Jaeger + Prometheus). Risultato: visibilità base su tracce e metriche.
Fase 2 (Settimana 3-6): Aggiunta di attributi custom sugli span critici, configurazione
del sampling, integrazione log-trace correlation. Risultato: debugging efficace per i flussi principali.
Fase 3 (Mese 2-3): Instrumentazione manuale per business metrics, dashboard Grafana
personalizzate, alerting basato su SLO. Risultato: observability production-grade.
Conclusioni e Prossimi Passi
OpenTelemetry fornisce un'architettura modulare e vendor-neutral che separa chiaramente l'instrumentazione (API), la raccolta (SDK), il routing (Collector) e l'esportazione (OTLP). Le Semantic Conventions garantiscono interoperabilità, mentre il supporto multi-linguaggio permette di adottare OTel in qualsiasi stack tecnologico.
La separazione API/SDK e la chiave architetturale: le librerie usano l'API (zero overhead senza SDK), le applicazioni configurano l'SDK con gli exporter appropriati. Questo design permette di instrumentare tutto l'ecosistema senza creare dipendenze forzate.
Nel prossimo articolo approfondiremo il distributed tracing, analizzando in dettaglio gli span, il trace context, il protocollo W3C Trace Context e le relazioni parent-child che formano il grafo di una traccia distribuita.







