Aller au contenu
Outils medium

OpenTelemetry : Instrumentation universelle

15 min de lecture

logo opentelemetry

OpenTelemetry (OTel) est le standard pour instrumenter vos applications. Vous générez traces, métriques et logs une seule fois, puis vous les envoyez vers n’importe quel backend : pas de vendor lock-in, pas de ré-instrumentation si vous changez de stack.

Cette page vous guide de votre première trace jusqu’à une configuration production-ready.

QuestionRéponse
C’est quoi ?Un ensemble d’APIs, SDKs et outils pour générer de la télémétrie (traces, métriques, logs)
Qui le maintient ?CNCF (Cloud Native Computing Foundation) — statut Incubating, graduation en cours
Pourquoi l’utiliser ?Standard unique, multi-langage, multi-backend, communauté active
Quels backends ?Jaeger, Tempo, Prometheus, Mimir, Loki, Datadog, New Relic, Splunk…

Avant de coder, comprenez les 5 couches :

Couches OpenTelemetry : du code applicatif aux backends

CoucheCe qu’elle faitOù elle vit
APIInterface pour créer spans, métriques, logsDans votre code
SDKImplémentation : buffering, sampling, exportRuntime de l’app
Auto-instrumentationInstrumente automatiquement les frameworksAgent/wrapper autour de l’app
Exporter OTLPEnvoie les signaux en OTLPDans l’app (SDK)
CollectorReçoit, transforme, routeInfrastructure (container/daemon)

Objectif : voir une trace passer avant de coder quoi que ce soit.

  1. Lancez un Collector avec export debug

    Fenêtre de terminal
    docker run --rm -p 4317:4317 -p 4318:4318 \
    otel/opentelemetry-collector-contrib:latest \
    --config='
    receivers:
    otlp:
    protocols:
    grpc:
    endpoint: 0.0.0.0:4317
    http:
    endpoint: 0.0.0.0:4318
    exporters:
    debug:
    verbosity: detailed
    service:
    pipelines:
    traces:
    receivers: [otlp]
    exporters: [debug]
    '

    Le Collector affiche les traces reçues dans la console.

  2. Envoyez une trace de test

    Avec telemetrygen (outil de test OTel) :

    Fenêtre de terminal
    docker run --rm --network host ghcr.io/open-telemetry/opentelemetry-collector-contrib/telemetrygen:latest \
    traces --otlp-insecure --traces 1
  3. Vérifiez la sortie

    Vous devez voir dans les logs du Collector :

    Trace ID: ...
    Span #0
    Name: otelgen
    Kind: SPAN_KIND_INTERNAL

Vous avez un pipeline fonctionnel. Maintenant, instrumentons une vraie application.

ModeQuand l’utiliserCe que ça couvre
Auto-instrumentationDémarrage rapide, legacy, frameworks standardsHTTP, SQL, Redis, Kafka, gRPC…
Instrumentation manuelleLogique métier, spans personnalisésCheckout, paiement, génération PDF…
Les deuxProduction réelleAuto = “plomberie”, manuel = “métier”

L’auto-instrumentation injecte des traces sans modifier votre code pour les frameworks courants (HTTP, DB, messaging).

Fenêtre de terminal
# Installer la distro (inclut SDK + instrumentations courantes)
pip install opentelemetry-distro
opentelemetry-bootstrap -a install
# Lancer en auto-instrumentation
opentelemetry-instrument python app.py

Configuration via env vars (recommandé) :

Fenêtre de terminal
export OTEL_SERVICE_NAME=checkout-api
export OTEL_EXPORTER_OTLP_ENDPOINT=http://otel-collector:4317
# Optionnel : debug local
export OTEL_TRACES_EXPORTER=console

L’auto couvre les “tuyaux” (HTTP, DB). Pour tracer la logique métier, ajoutez des spans manuels.

from opentelemetry import trace
tracer = trace.get_tracer(__name__)
def process_checkout(cart_id: str, user_id: str):
with tracer.start_as_current_span("checkout.process") as span:
# Attributs métier
span.set_attribute("cart.id", cart_id)
span.set_attribute("user.id", user_id)
span.set_attribute("cart.items_count", 5)
# Span enfant
with tracer.start_as_current_span("checkout.validate_payment"):
validate_payment()
with tracer.start_as_current_span("checkout.reserve_stock"):
reserve_stock()
from opentelemetry.trace import Status, StatusCode
try:
result = process_payment()
except Exception as e:
span.set_status(Status(StatusCode.ERROR, str(e)))
span.record_exception(e)
raise

Ne hardcodez pas les endpoints. Utilisez les variables d’environnement standard OTel :

Fenêtre de terminal
# Identité du service (obligatoire)
OTEL_SERVICE_NAME=checkout-api
OTEL_RESOURCE_ATTRIBUTES=service.version=1.2.0,deployment.environment=production
# Export OTLP
OTEL_EXPORTER_OTLP_ENDPOINT=http://otel-collector:4317
OTEL_EXPORTER_OTLP_PROTOCOL=grpc # ou http/protobuf
# Sampling (production)
OTEL_TRACES_SAMPLER=parentbased_traceidratio
OTEL_TRACES_SAMPLER_ARG=0.1 # 10% des traces
# Propagation
OTEL_PROPAGATORS=tracecontext,baggage
# Debug (dev uniquement)
OTEL_TRACES_EXPORTER=console # affiche dans stdout
OTEL_LOG_LEVEL=debug # logs détaillés du SDK

En production, tracer 100% des requêtes = coûts explosifs et overhead.

SamplerDescription
always_onTout (dev uniquement)
traceidratioX% des traces
parentbased_traceidratioX% sauf si parent a décidé (recommandé)
Fenêtre de terminal
OTEL_TRACES_SAMPLER=parentbased_traceidratio
OTEL_TRACES_SAMPLER_ARG=0.1 # 10%

La propagation transmet le trace-id entre services. Sans elle, vos traces sont fragmentées.

traceparent: 00-0af7651916cd43dd8448eb211c80319c-b7ad6b7169203331-01

Par défaut, OTel utilise W3C Trace Context. Si vous avez du legacy B3 (Zipkin) :

Fenêtre de terminal
OTEL_PROPAGATORS=tracecontext,baggage,b3multi

Utilisez les Semantic Conventions pour des attributs interopérables :

DomaineAttributs
HTTPhttp.request.method, url.path, http.response.status_code
Databasedb.system, db.name, db.operation, db.statement
Messagingmessaging.system, messaging.destination.name

Injectez trace_id et span_id dans vos logs pour les corréler :

{
"timestamp": "2026-02-09T10:30:00Z",
"level": "ERROR",
"message": "Payment failed: insufficient funds",
"trace_id": "abc123def456...",
"span_id": "789xyz...",
"service.name": "payment-service"
}

En production, ne pas exporter directement vers les backends. Passez par un Collector :

App (SDK) → OTLP → Collector → Backends

Pourquoi ?

  • Découplage : changez de backend sans recoder
  • Résilience : le Collector bufferise si backend down
  • Gouvernance : filtrage, redaction PII, enrichissement K8s
  • Multi-destinations : traces → Tempo, métriques → Mimir
Anti-patternConséquenceSolution
IDs uniques en attributsExplosion cardinalité, coûtsUtiliser des catégories (status, region)
Tracer 100% en prodOverhead, coûts stockageSampling 10-20%
PII/secrets en attributsFuite de donnéesRedaction via Collector
Exporter direct vers backendVendor lock-in, pas de gouvernancePasser par Collector
Pas de service.nameTraces anonymes, inutilisablesToujours définir OTEL_SERVICE_NAME
Ignorer la propagationSpans orphelins, traces fragmentéesVérifier propagators + headers
Spans trop verbeuxBruit, difficile à exploiter5-10 attributs max par span
  1. Le SDK génère-t-il des spans ?

    Fenêtre de terminal
    OTEL_TRACES_EXPORTER=console python app.py
    # → Vous devez voir des spans dans stdout
  2. Le Collector reçoit-il les données ?

    Activez le debug exporter dans le Collector :

    exporters:
    debug:
    verbosity: detailed
  3. Le réseau est-il OK ?

    Fenêtre de terminal
    # Depuis le container de l'app
    curl -v http://otel-collector:4318/v1/traces
    # → Doit répondre (même en erreur 405)
  4. Les ports sont-ils corrects ?

    • 4317 = gRPC
    • 4318 = HTTP

    Vérifiez que OTEL_EXPORTER_OTLP_PROTOCOL correspond.

  5. La propagation est-elle configurée ?

    Sans propagation, les services ne partagent pas le trace-id.

    Fenêtre de terminal
    OTEL_PROPAGATORS=tracecontext,baggage
SymptômeCause probableSolution
Connection refused :4317Collector non démarré ou mauvais portVérifier le container/service
Spans orphelins (pas de parent)Propagation manquanteVérifier OTEL_PROPAGATORS
Traces fragmentéesContext perdu entre appels asyncUtiliser context.with_span()
”Unknown service” dans le backendOTEL_SERVICE_NAME non définiDéfinir la variable

OTel supporte aussi les métriques. Les types de base :

TypeUsageExemple
CounterValeurs cumulativesRequêtes, erreurs
GaugeValeur instantanéeMémoire, connexions actives
HistogramDistributionLatence (p50, p95, p99)
from opentelemetry import metrics
meter = metrics.get_meter(__name__)
# Counter
request_counter = meter.create_counter("http.server.requests")
request_counter.add(1, {"method": "GET", "status": "200"})
# Histogram (latence)
latency_histogram = meter.create_histogram("http.server.duration", unit="ms")
latency_histogram.record(45.2, {"method": "GET", "route": "/api/orders"})
  • OTel = standard CNCF pour traces, métriques, logs — choisissez-le par défaut
  • Auto-instrumentation couvre 80% sans modifier le code
  • Spans manuels pour la logique métier (checkout, paiement…)
  • Configurez via env vars (OTEL_*), pas en dur dans le code
  • Passez par un Collector en production (découplage, gouvernance)
  • Sampling + redaction = obligatoires en prod

Ce site vous est utile ?

Sachez que moins de 1% des lecteurs soutiennent ce site.

Je maintiens +700 guides gratuits, sans pub ni tracing. Aujourd'hui, ce site ne couvre même pas mes frais d'hébergement, d'électricité, de matériel, de logiciels, mais surtout de cafés.

Un soutien régulier, même symbolique, m'aide à garder ces ressources gratuites et à continuer de produire des guides de qualité. Merci pour votre appui.