TL;DR — Résumé Rapide
OpenTelemetry unifie traces, métriques et logs sous un standard neutre. Maîtrisez le Collector OTel, l'instrumentation automatique et les backends Grafana.
OpenTelemetry (OTel) est le standard CNCF open-source qui unifie la collecte de traces, métriques et logs sous une API, un SDK et un protocole réseau neutres vis-à-vis du fournisseur. Avant OTel, chaque éditeur d’observabilité — Datadog, New Relic, Dynatrace, Elastic — nécessitait son propre agent propriétaire, obligeant les équipes à instrumenter le code plusieurs fois. OTel brise cette dépendance : instrumentez une fois, envoyez vers n’importe quel backend. Ce guide couvre l’architecture complète d’OTel, la configuration du Collector, l’instrumentation automatique et manuelle, le tracing distribué, les patterns de déploiement Kubernetes et un exemple pratique de microservices Node.js + Python avec Grafana.
Prérequis
- Familiarité avec Docker et Kubernetes basique (pour les sections Kubernetes)
- Une application cible en Node.js, Python, Java, .NET ou Go
- Docker Compose ou un cluster Kubernetes pour l’exemple pratique
- Compréhension de base de ce que sont les traces, métriques et logs conceptuellement
kubectlconfiguré si vous utilisez les sections de l’opérateur Kubernetes
Architecture d’OpenTelemetry
OTel est organisé en trois couches clairement séparées :
API — Interfaces spécifiques au langage (ex. : tracer.startSpan()). C’est ce qu’appelle le code de votre application. L’API seule ne fait rien ; elle a besoin d’une implémentation SDK injectée à l’exécution.
SDK — L’implémentation de l’API. Le SDK gère les décisions d’échantillonnage, la détection de ressources (hostname, nom du pod k8s, région cloud) et l’export de télémétrie via OTLP.
Collector — Un binaire autonome (ou conteneur Docker) qui agit comme pipeline de télémétrie : reçoit des apps → traite → exporte vers les backends.
OTLP (OpenTelemetry Line Protocol) est le format réseau canonique : protobuf sur gRPC (port 4317) ou HTTP/JSON (port 4318).
Le Collector OpenTelemetry
Le Collector est le composant le plus puissant d’un déploiement OTel en production, fonctionnant comme un pipeline à trois étapes :
Receivers
receivers:
otlp:
protocols:
grpc:
endpoint: "0.0.0.0:4317"
http:
endpoint: "0.0.0.0:4318"
prometheus:
config:
scrape_configs:
- job_name: "mon-app"
static_configs:
- targets: ["app:8080"]
filelog:
include: ["/var/log/app/*.log"]
operators:
- type: json_parser
hostmetrics:
collection_interval: 30s
scrapers:
cpu: {}
memory: {}
disk: {}
network: {}
Processors
processors:
memory_limiter:
check_interval: 1s
limit_mib: 400
batch:
send_batch_size: 10000
timeout: 10s
attributes:
actions:
- key: environment
value: production
action: insert
filter:
traces:
span:
- 'attributes["http.target"] == "/health"'
tail_sampling:
decision_wait: 10s
policies:
- name: politique-erreurs
type: status_code
status_code: {status_codes: [ERROR]}
- name: politique-traces-lentes
type: latency
latency: {threshold_ms: 1000}
- name: politique-probabiliste
type: probabilistic
probabilistic: {sampling_percentage: 10}
Le tail_sampling s’exécute dans le Collector et prend des décisions après avoir vu la trace complète, capturant toutes les erreurs tout en n’échantillonnant qu’une fraction des traces saines.
Exporters et Pipelines
exporters:
otlp/tempo:
endpoint: "tempo:4317"
tls:
insecure: true
prometheus:
endpoint: "0.0.0.0:9464"
loki:
endpoint: "http://loki:3100/loki/api/v1/push"
service:
pipelines:
traces:
receivers: [otlp]
processors: [memory_limiter, batch, tail_sampling]
exporters: [otlp/tempo]
metrics:
receivers: [otlp, prometheus, hostmetrics]
processors: [memory_limiter, batch, attributes]
exporters: [prometheus]
logs:
receivers: [otlp, filelog]
processors: [memory_limiter, batch]
exporters: [loki]
Auto-Instrumentation
L’auto-instrumentation ajoute OTel sans modifier le code de l’application, interceptant automatiquement les appels HTTP, base de données et messagerie.
Java — Exécutez l’agent Java OTel comme flag JVM :
java -javaagent:/otel-javaagent.jar \
-Dotel.service.name=mon-service \
-Dotel.exporter.otlp.endpoint=http://collector:4317 \
-jar mon-app.jar
Python — Utilisez opentelemetry-instrument :
pip install opentelemetry-distro opentelemetry-exporter-otlp
opentelemetry-bootstrap --action=install
opentelemetry-instrument \
--service_name mon-service \
--exporter_otlp_endpoint http://collector:4317 \
python app.py
Node.js — Importez le SDK avant tout code applicatif :
// tracing.js — doit être chargé en premier via --require
const { NodeSDK } = require('@opentelemetry/sdk-node');
const { getNodeAutoInstrumentations } = require('@opentelemetry/auto-instrumentations-node');
const { OTLPTraceExporter } = require('@opentelemetry/exporter-trace-otlp-grpc');
const sdk = new NodeSDK({
serviceName: 'mon-service-node',
traceExporter: new OTLPTraceExporter({ url: 'http://collector:4317' }),
instrumentations: [getNodeAutoInstrumentations()],
});
sdk.start();
Instrumentation Manuelle
Création de Spans
const opentelemetry = require('@opentelemetry/api');
const tracer = opentelemetry.trace.getTracer('mon-service', '1.0.0');
async function traiterCommande(commandeId) {
return tracer.startActiveSpan('traiterCommande', async (span) => {
try {
span.setAttribute('commande.id', commandeId);
const resultat = await debiterPaiement(commandeId);
span.addEvent('paiement.debite', { 'paiement.montant': resultat.montant });
return resultat;
} catch (err) {
span.recordException(err);
span.setStatus({ code: opentelemetry.SpanStatusCode.ERROR });
throw err;
} finally {
span.end();
}
});
}
Création de Métriques
const meter = opentelemetry.metrics.getMeter('mon-service', '1.0.0');
const compteurRequetes = meter.createCounter('http.server.requests');
const histogrammLatence = meter.createHistogram('http.server.duration', { unit: 'ms' });
const connexionsActives = meter.createUpDownCounter('db.connections.active');
meter.createObservableGauge('process.memory.usage').addCallback((result) => {
result.observe(process.memoryUsage().heapUsed);
});
Tracing Distribué
Une trace est un graphe acyclique dirigé de spans représentant une requête de bout en bout. Chaque span possède : TraceId, SpanId, ParentSpanId, SpanKind, attributs, événements et statut.
Échantillonnage en tête — décide au span racine, simple mais ne peut pas favoriser les traces lentes ou erronées. Échantillonnage en queue — collecte la trace complète d’abord, puis décide de la conserver en capturant 100% des erreurs et seulement 10% du trafic sain.
Les exemplaires relient les observations d’histogramme Prometheus à des TraceIds Tempo spécifiques, permettant la navigation en un clic depuis un pic de latence P99 directement vers une trace représentative.
Kubernetes avec l’OTel Operator
apiVersion: opentelemetry.io/v1alpha1
kind: Instrumentation
metadata:
name: otel-instrumentation
spec:
exporter:
endpoint: http://otel-agent:4317
propagators: [tracecontext, baggage]
sampler:
type: parentbased_traceidratio
argument: "0.1"
nodejs:
image: ghcr.io/open-telemetry/opentelemetry-operator/autoinstrumentation-nodejs:latest
python:
image: ghcr.io/open-telemetry/opentelemetry-operator/autoinstrumentation-python:latest
Annotez un Deployment pour injecter l’agent Node.js automatiquement :
annotations:
instrumentation.opentelemetry.io/inject-nodejs: "true"
Backends et Comparaison
| Backend | Signaux | Stockage |
|---|---|---|
| Jaeger | Traces uniquement | Cassandra/Elasticsearch |
| Prometheus | Métriques uniquement | TSDB local |
| Grafana Loki | Logs uniquement | Stockage d’objets |
| Grafana Tempo | Traces uniquement | Stockage d’objets |
| SigNoz | Traces + Métriques + Logs | ClickHouse |
| Plateforme | Lock-in | Modèle de coût |
|---|---|---|
| OpenTelemetry + Grafana | Aucun | Gratuit (auto-hébergé) |
| Datadog | Élevé | Par hôte + ingestion |
| New Relic | Moyen | Par Go ingéré |
| Dynatrace | Très élevé | Par unité hôte |
| Elastic APM | Moyen | Par Go |
Exemple Pratique : Node.js + Python avec Grafana Stack
Une configuration à deux services : un gateway API Node.js qui appelle un service de commandes Python. Toute la télémétrie passe par un seul Collector vers Tempo, Prometheus et Loki, visualisés dans Grafana.
services:
collector:
image: otel/opentelemetry-collector-contrib:latest
volumes:
- ./collector-config.yaml:/etc/otel/config.yaml
ports: ["4317:4317", "4318:4318", "9464:9464"]
node-api:
environment:
- OTEL_EXPORTER_OTLP_ENDPOINT=http://collector:4317
- OTEL_SERVICE_NAME=node-api
python-commandes:
environment:
- OTEL_EXPORTER_OTLP_ENDPOINT=http://collector:4317
- OTEL_SERVICE_NAME=python-commandes
Dans Grafana : ouvrez Explore → Tempo → recherchez par service.name=node-api → cliquez sur une trace → utilisez le lien exemplaire pour voir la métrique P95 Prometheus corrélée → cliquez sur le lien Loki pour voir la ligne de log exacte de cette requête.
Pièges et Cas Particuliers
Dérive d’horloge — Les traces distribuées dépendent d’horloges synchronisées. Une dérive NTP supérieure à 1ms cause des problèmes d’ordonnancement des spans. Utilisez chrony ou la synchronisation temporelle native du cloud.
Tail sampling nécessite un routage cohérent par TraceId — Si vous exécutez plusieurs réplicas du Collector gateway avec tail_sampling, tous les spans de la même trace doivent arriver à la même instance. Utilisez l’exporter loadbalancing avec routing_key: traceId.
Explosion de cardinalité — N’utilisez jamais des valeurs de haute cardinalité (IDs utilisateur, IDs commande) comme valeurs de labels de métriques. Les attributs OTel sur les spans sont sûrs à toute cardinalité ; les dimensions de métriques ne le sont pas.
Résumé
- OpenTelemetry fournit une API, un SDK et un protocole réseau (OTLP) uniques et neutres pour traces, métriques et logs
- Le Collector OTel découple les applications des backends ; utilisez des agents (DaemonSet) alimentant un gateway (Deployment) avec tail sampling en production
- L’auto-instrumentation ajoute des traces sans changement de code ; l’instrumentation manuelle ajoute du contexte métier avec
startActiveSpanetcreateCounter/createHistogram - Les exemplaires relient les observations de métriques Prometheus aux TraceIds Tempo pour un drill-down en un clic
- La Grafana Stack (Tempo + Prometheus + Loki + Grafana) est la combinaison de backends OTel open-source la plus populaire