OpenTelemetry est devenu le standard d'observabilité cloud-native. Traces, métriques et logs unifiés en un seul SDK — découvrez comment l'implémenter en production avec Grafana Tempo.
Pourquoi OpenTelemetry ?
Avant OpenTelemetry, chaque outil d'observabilité avait son propre SDK propriétaire : Jaeger SDK, Zipkin SDK, Datadog Agent, New Relic SDK. Instrumenter une application signifiait choisir un vendor dès le départ, avec un couplage fort et des coûts de migration prohibitifs. OpenTelemetry (OTel) résout ce problème fondamental en proposant un SDK unique, vendor-neutral, qui devient le standard de facto du CNCF.
OTel unifie les trois signaux d'observabilité dans une seule API :
- Traces : suivi de bout en bout d'une requête à travers plusieurs services (spans)
- Métriques : compteurs, jauges, histogrammes exposés en format OTLP ou Prometheus
- Logs : logs structurés avec corrélation automatique aux traces via Trace ID
Architecture OTel
La chaîne de collecte OTel suit ce flux :
Application (SDK OTel)
│ OTLP gRPC/HTTP
▼
OTel Collector (pipeline)
├── Receivers : OTLP, Prometheus, Jaeger, Zipkin, Fluentd
├── Processors : batch, memory_limiter, resource, sampling
└── Exporters : Tempo (traces), Prometheus (métriques), Loki (logs)
│
├── Grafana Tempo → Traces
├── Prometheus → Métriques
└── Grafana Loki → Logs
Auto-instrumentation Node.js
OTel propose des librairies d'auto-instrumentation qui patchent automatiquement les modules populaires (Express, HTTP, gRPC, Redis, PostgreSQL) sans modifier le code applicatif :
// tracing.ts — à charger AVANT tout autre module
import { NodeSDK } from '@opentelemetry/sdk-node';
import { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-grpc';
import { OTLPMetricExporter } from '@opentelemetry/exporter-metrics-otlp-grpc';
import { PeriodicExportingMetricReader } from '@opentelemetry/sdk-metrics';
import { getNodeAutoInstrumentations } from '@opentelemetry/auto-instrumentations-node';
import { Resource } from '@opentelemetry/resources';
import { SemanticResourceAttributes } from '@opentelemetry/semantic-conventions';
const sdk = new NodeSDK({
resource: new Resource({
[SemanticResourceAttributes.SERVICE_NAME]: 'payment-service',
[SemanticResourceAttributes.SERVICE_VERSION]: process.env.APP_VERSION,
[SemanticResourceAttributes.DEPLOYMENT_ENVIRONMENT]: process.env.NODE_ENV,
}),
traceExporter: new OTLPTraceExporter({
url: 'http://otel-collector:4317',
}),
metricReader: new PeriodicExportingMetricReader({
exporter: new OTLPMetricExporter({ url: 'http://otel-collector:4317' }),
exportIntervalMillis: 15000,
}),
instrumentations: [getNodeAutoInstrumentations()],
});
sdk.start();
process.on('SIGTERM', () => sdk.shutdown());
# package.json — démarrage avec auto-instrumentation
{
"scripts": {
"start": "node --require ./tracing.js dist/server.js"
}
}
Configuration du OTel Collector
Le Collector est le composant central qui reçoit, transforme et exporte les signaux vers les backends :
# otel-collector-config.yaml
receivers:
otlp:
protocols:
grpc:
endpoint: 0.0.0.0:4317
http:
endpoint: 0.0.0.0:4318
prometheus:
config:
scrape_configs:
- job_name: 'kubernetes-pods'
kubernetes_sd_configs:
- role: pod
processors:
batch:
timeout: 5s
send_batch_size: 1024
memory_limiter:
limit_mib: 512
spike_limit_mib: 128
resource:
attributes:
- key: deployment.environment
value: production
action: upsert
tail_sampling:
decision_wait: 10s
policies:
- name: errors-policy
type: status_code
status_code: {status_codes: [ERROR]}
- name: slow-traces
type: latency
latency: {threshold_ms: 500}
- name: probabilistic
type: probabilistic
probabilistic: {sampling_percentage: 10}
exporters:
otlp/tempo:
endpoint: http://tempo:4317
tls:
insecure: true
prometheusremotewrite:
endpoint: http://prometheus:9090/api/v1/write
loki:
endpoint: http://loki:3100/loki/api/v1/push
service:
pipelines:
traces:
receivers: [otlp]
processors: [memory_limiter, batch, resource, tail_sampling]
exporters: [otlp/tempo]
metrics:
receivers: [otlp, prometheus]
processors: [memory_limiter, batch]
exporters: [prometheusremotewrite]
logs:
receivers: [otlp]
processors: [memory_limiter, batch]
exporters: [loki]
Grafana Tempo comme backend de traces
Tempo est le backend de traces distribué de Grafana Labs, conçu pour stocker massivement des traces à bas coût en utilisant S3/GCS comme stockage objet :
# values.yaml pour le chart Helm Tempo
tempo:
storage:
trace:
backend: s3
s3:
bucket: my-tempo-traces
region: eu-west-1
access_key: ${AWS_ACCESS_KEY_ID}
secret_key: ${AWS_SECRET_ACCESS_KEY}
retention: 168h # 7 jours
tempoQuery:
enabled: true
helm repo add grafana https://grafana.github.io/helm-charts
helm upgrade --install tempo grafana/tempo -f values.yaml --namespace monitoring
Corrélation traces ↔ logs ↔ métriques dans Grafana
La puissance d'OTel réside dans la corrélation automatique des trois signaux. Dans Grafana, configurez les datasources pour activer la navigation entre signaux :
- Trace to Logs : depuis une trace Tempo, ouvrir les logs Loki filtrés par
traceID - Trace to Metrics : depuis une trace, voir les métriques Prometheus du service à ce moment précis
- Exemplars : depuis une métrique Prometheus, accéder directement à une trace représentative
Propagation du contexte W3C Trace Context
Pour les traces distribuées cross-services, OTel utilise le standard W3C Trace Context (RFC 7230). Les headers traceparent et tracestate sont automatiquement propagés par les SDK entre services HTTP et gRPC.
Stratégies de sampling
- Head-based sampling : décision prise à l'entrée de la trace (avant d'avoir les données complètes). Simple, faible overhead. Configurable par rate (10 % des traces).
- Tail-based sampling : décision prise après la fin de la trace (accès à toutes les données). Permet de conserver 100 % des traces en erreur et de sampler à 5 % les traces normales. Requiert plus de mémoire dans le Collector.
OTel Operator pour Kubernetes
L'OTel Operator permet d'auto-instrumenter des applications via une simple annotation Kubernetes, sans modifier le code ni les images Docker :
apiVersion: apps/v1
kind: Deployment
metadata:
name: payment-service
spec:
template:
metadata:
annotations:
instrumentation.opentelemetry.io/inject-nodejs: "true"
# Aussi disponible : inject-java, inject-python, inject-dotnet
spec:
containers:
- name: app
image: payment-service:1.0.0
# Configuration de l'Instrumentation CRD
apiVersion: opentelemetry.io/v1alpha1
kind: Instrumentation
metadata:
name: default-instrumentation
namespace: production
spec:
exporter:
endpoint: http://otel-collector:4317
propagators:
- tracecontext
- baggage
sampler:
type: parentbased_traceidratio
argument: "0.1" # 10 % sampling
Conclusion
OpenTelemetry a résolu le problème du vendor lock-in dans l'observabilité. Avec un seul SDK, vous pouvez changer de backend (Datadog → Grafana Stack, ou NewRelic → Jaeger) sans toucher au code applicatif. La stack open-source OTel Collector + Grafana Tempo + Prometheus + Loki offre une observabilité de niveau enterprise à coût maîtrisé sur Kubernetes.
