
L'OpenTelemetry Collector est un intermédiaire entre vos applications et vos backends d'observabilité. Au lieu d'envoyer directement vos traces à Jaeger, vos métriques à Prometheus et vos logs à Loki, vos applications envoient tout au Collector, et lui se charge de distribuer les données aux bons endroits.
Ce guide vous explique pourquoi l'utiliser, comment l'installer, et surtout comment connecter vos applications.
À quoi sert le Collector ?
Section intitulée « À quoi sert le Collector ? »Le problème sans Collector
Section intitulée « Le problème sans Collector »Imaginez une application Python qui doit envoyer :
- Des traces à Jaeger
- Des métriques à Prometheus
- Des logs à Loki
Sans Collector, votre code ressemble à ça :
# Chaque backend a son SDK, son format, sa configfrom jaeger_client import Config as JaegerConfigfrom prometheus_client import start_http_serverimport logging_loki
# 3 connexions différentes, 3 formats différentsjaeger_tracer = JaegerConfig(...).initialize_tracer()start_http_server(8000) # Endpoint Prometheusloki_handler = logging_loki.LokiHandler(url="http://loki:3100/...")Problèmes :
- Si vous changez de backend traces (Jaeger → Tempo), vous modifiez le code
- Chaque service a sa propre config de connexion
- Pas de filtrage, pas de transformation des données
La solution : le Collector comme intermédiaire
Section intitulée « La solution : le Collector comme intermédiaire »Avec l'OpenTelemetry Collector, vos applications envoient tout au même endroit :
Avantages :
- Code simplifié : votre app ne connaît qu'OTLP, pas les backends
- Changement de backend : modifiez la config du Collector, pas le code
- Transformation : filtrez, enrichissez, samplez les données avant envoi
- Résilience : le Collector bufferise si un backend est temporairement indisponible
Comprendre l'architecture
Section intitulée « Comprendre l'architecture »Le Collector fonctionne comme un pipeline avec trois étapes :
1. Receivers : recevoir les données
Section intitulée « 1. Receivers : recevoir les données »Les receivers écoutent sur des ports et ingèrent les données entrantes.
| Receiver | Ce qu'il reçoit | Port par défaut |
|---|---|---|
otlp | Traces, métriques, logs au format OpenTelemetry | 4317 (gRPC), 4318 (HTTP) |
jaeger | Traces au format Jaeger | 14268 |
prometheus | Métriques scrapées depuis des endpoints | - |
filelog | Logs depuis des fichiers | - |
En pratique : utilisez otlp pour vos nouvelles applications. Les autres receivers servent à intégrer des outils existants.
2. Processors : transformer les données
Section intitulée « 2. Processors : transformer les données »Les processors modifient les données entre réception et envoi.
| Processor | Ce qu'il fait | Quand l'utiliser |
|---|---|---|
batch | Regroupe les données (réduit le trafic réseau) | Toujours |
memory_limiter | Évite les OOM en limitant la mémoire | Toujours |
filter | Supprime les données inutiles | Réduire les coûts |
attributes | Ajoute/supprime des métadonnées | Enrichir ou masquer des données sensibles |
k8sattributes | Ajoute les métadonnées Kubernetes (pod, namespace…) | Sur Kubernetes |
3. Exporters : envoyer aux backends
Section intitulée « 3. Exporters : envoyer aux backends »Les exporters transmettent les données aux backends finaux.
| Exporter | Destination | Quand l'utiliser |
|---|---|---|
otlp | Tout backend compatible OTLP (Tempo, Jaeger, Honeycomb…) | Traces et métriques |
prometheusremotewrite | Prometheus, Mimir, Cortex | Métriques |
loki | Loki | Logs |
debug | Console (stdout) | Dépannage |
Installer le Collector
Section intitulée « Installer le Collector »-
Créez un fichier de configuration
config.yaml receivers:otlp:protocols:grpc:endpoint: 0.0.0.0:4317http:endpoint: 0.0.0.0:4318processors:memory_limiter:check_interval: 1slimit_mib: 512spike_limit_mib: 128batch:timeout: 5sexporters:debug:verbosity: detailedextensions:health_check:endpoint: 0.0.0.0:13133zpages:endpoint: 0.0.0.0:55679service:extensions: [health_check, zpages]pipelines:traces:receivers: [otlp]processors: [memory_limiter, batch]exporters: [debug]Cette config minimale :
- Écoute OTLP sur les ports 4317 (gRPC) et 4318 (HTTP)
- Limite la mémoire (
memory_limiter) pour éviter les OOM - Regroupe les données par batch de 5 secondes
- Active
health_check(port 13133) etzpages(port 55679) pour le diagnostic - Affiche les traces dans la console (pour vérifier que ça marche)
-
Lancez le Collector
Fenêtre de terminal docker run -d \--name otel-collector \-p 127.0.0.1:4317:4317 \-p 127.0.0.1:4318:4318 \-p 127.0.0.1:13133:13133 \-v $(pwd)/config.yaml:/etc/otelcol-contrib/config.yaml:ro \otel/opentelemetry-collector-contrib:0.145.0 -
Vérifiez qu'il fonctionne
Fenêtre de terminal # Vérifier les logsdocker logs otel-collector# Vérifier le health checkcurl http://localhost:13133/Ce que vous devez voir :
2026-02-09T10:00:00.000Z info service@v0.145.0/service.go:140 Starting otelcol-contrib...2026-02-09T10:00:00.100Z info service@v0.145.0/service.go:267 Everything is ready. Begin running and processing data.Le health check retourne :
{"status":"Server available"}Si vous voyez
Everything is readyet le health check passe, le Collector est opérationnel.
-
Ajoutez le repo Helm
Fenêtre de terminal helm repo add open-telemetry https://open-telemetry.github.io/opentelemetry-helm-chartshelm repo update -
Créez un fichier values.yaml
values.yaml mode: deployment # ou daemonset pour collecter par nodeconfig:receivers:otlp:protocols:grpc:endpoint: 0.0.0.0:4317http:endpoint: 0.0.0.0:4318processors:batch:timeout: 5smemory_limiter:check_interval: 1slimit_mib: 512exporters:debug:verbosity: detailedservice:pipelines:traces:receivers: [otlp]processors: [memory_limiter, batch]exporters: [debug] -
Installez
Fenêtre de terminal helm install otel-collector open-telemetry/opentelemetry-collector \--namespace observability \--create-namespace \-f values.yaml -
Vérifiez
Fenêtre de terminal kubectl get pods -n observability -l app.kubernetes.io/name=opentelemetry-collectorLe pod doit être en
Running.
-
Téléchargez
Fenêtre de terminal # Dernière version stable (février 2026)VERSION="0.145.0"curl -LO "https://github.com/open-telemetry/opentelemetry-collector-releases/releases/download/v${VERSION}/otelcol-contrib_${VERSION}_linux_amd64.tar.gz"tar -xzf otelcol-contrib_${VERSION}_linux_amd64.tar.gz -
Créez la config (même contenu que pour Docker)
Fenêtre de terminal cat > config.yaml << 'EOF'receivers:otlp:protocols:grpc:endpoint: 0.0.0.0:4317http:endpoint: 0.0.0.0:4318processors:batch:timeout: 5sexporters:debug:verbosity: detailedservice:pipelines:traces:receivers: [otlp]processors: [batch]exporters: [debug]EOF -
Lancez
Fenêtre de terminal ./otelcol-contrib --config config.yaml -
Validez la configuration (optionnel mais recommandé)
Fenêtre de terminal ./otelcol-contrib validate --config config.yaml
Votre premier pipeline : traces vers Jaeger
Section intitulée « Votre premier pipeline : traces vers Jaeger »Maintenant que le Collector tourne, configurons un pipeline réaliste qui envoie les traces vers Jaeger.
Prérequis
Section intitulée « Prérequis »Vous avez besoin de Jaeger. Créez un réseau Docker pour éviter les conflits de ports :
# Créer un réseau partagédocker network create observability
# Lancer Jaeger (uniquement l'UI exposée)docker run -d --name jaeger \ --network observability \ -p 16686:16686 \ jaegertracing/all-in-one:1.64L'interface Jaeger est sur http://localhost:16686
Configuration
Section intitulée « Configuration »Modifiez votre config.yaml :
receivers: otlp: protocols: grpc: endpoint: 0.0.0.0:4317 http: endpoint: 0.0.0.0:4318
processors: memory_limiter: check_interval: 1s limit_mib: 512 spike_limit_mib: 128 batch: timeout: 5s send_batch_size: 1000
exporters: # Exporter vers Jaeger via OTLP otlp/jaeger: endpoint: jaeger:4317 tls: insecure: true
# Garder le debug pour voir ce qui passe debug: verbosity: basic
extensions: health_check: endpoint: 0.0.0.0:13133 zpages: endpoint: 0.0.0.0:55679
service: extensions: [health_check, zpages] pipelines: traces: receivers: [otlp] processors: [memory_limiter, batch] exporters: [otlp/jaeger, debug]Ce qui se passe :
- Les applications envoient des traces OTLP au Collector (port 4317 ou 4318)
- Le Collector limite la mémoire (
memory_limiter) pour éviter les OOM - Les traces sont regroupées par batch de 1000 ou toutes les 5 secondes
- Les traces sont envoyées à Jaeger ET affichées dans les logs (debug)
Redémarrez le Collector
Section intitulée « Redémarrez le Collector »# Arrêter l'ancien collectordocker stop otel-collector && docker rm otel-collector
# Relancer avec le réseau et la nouvelle configdocker run -d \ --name otel-collector \ --network observability \ -p 127.0.0.1:4317:4317 \ -p 127.0.0.1:4318:4318 \ -p 127.0.0.1:13133:13133 \ -v $(pwd)/config.yaml:/etc/otelcol-contrib/config.yaml:ro \ otel/opentelemetry-collector-contrib:0.145.0Connecter vos applications au Collector
Section intitulée « Connecter vos applications au Collector »C'est la partie la plus importante : comment vos applications envoient-elles des données au Collector ?
Option 1 : SDK OpenTelemetry (recommandé)
Section intitulée « Option 1 : SDK OpenTelemetry (recommandé) »Installez le SDK OpenTelemetry dans votre application et configurez l'endpoint.
pip install opentelemetry-api opentelemetry-sdk opentelemetry-exporter-otlpfrom opentelemetry import tracefrom opentelemetry.sdk.trace import TracerProviderfrom opentelemetry.sdk.trace.export import BatchSpanProcessorfrom opentelemetry.exporter.otlp.proto.grpc.trace_exporter import OTLPSpanExporter
# Configurer l'exporter OTLP vers le Collectorotlp_exporter = OTLPSpanExporter( endpoint="http://localhost:4317", # Adresse du Collector insecure=True)
# Configurer le tracerprovider = TracerProvider()provider.add_span_processor(BatchSpanProcessor(otlp_exporter))trace.set_tracer_provider(provider)
# Utilisertracer = trace.get_tracer(__name__)
with tracer.start_as_current_span("mon-operation"): # Votre code ici print("Cette opération est tracée !")npm install @opentelemetry/api @opentelemetry/sdk-node @opentelemetry/exporter-trace-otlp-grpcconst { NodeSDK } = require('@opentelemetry/sdk-node');const { OTLPTraceExporter } = require('@opentelemetry/exporter-trace-otlp-grpc');
const sdk = new NodeSDK({ traceExporter: new OTLPTraceExporter({ url: 'http://localhost:4317', // Adresse du Collector }),});
sdk.start();
// Dans votre codeconst opentelemetry = require('@opentelemetry/api');const tracer = opentelemetry.trace.getTracer('mon-service');
const span = tracer.startSpan('mon-operation');// Votre codespan.end();go get go.opentelemetry.io/otelgo get go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpcpackage main
import ( "context" "go.opentelemetry.io/otel" "go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc" "go.opentelemetry.io/otel/sdk/trace")
func main() { ctx := context.Background()
// Configurer l'exporter OTLP exporter, _ := otlptracegrpc.New(ctx, otlptracegrpc.WithEndpoint("localhost:4317"), otlptracegrpc.WithInsecure(), )
// Configurer le tracer provider tp := trace.NewTracerProvider( trace.WithBatcher(exporter), ) otel.SetTracerProvider(tp)
// Utiliser tracer := otel.Tracer("mon-service") _, span := tracer.Start(ctx, "mon-operation") defer span.End()}<dependency> <groupId>io.opentelemetry</groupId> <artifactId>opentelemetry-sdk</artifactId> <version>1.32.0</version></dependency><dependency> <groupId>io.opentelemetry</groupId> <artifactId>opentelemetry-exporter-otlp</artifactId> <version>1.32.0</version></dependency>import io.opentelemetry.api.trace.Tracer;import io.opentelemetry.api.trace.Span;import io.opentelemetry.exporter.otlp.trace.OtlpGrpcSpanExporter;import io.opentelemetry.sdk.trace.SdkTracerProvider;import io.opentelemetry.sdk.trace.export.BatchSpanProcessor;
public class Application { public static void main(String[] args) { // Configurer l'exporter OtlpGrpcSpanExporter exporter = OtlpGrpcSpanExporter.builder() .setEndpoint("http://localhost:4317") .build();
SdkTracerProvider tracerProvider = SdkTracerProvider.builder() .addSpanProcessor(BatchSpanProcessor.builder(exporter).build()) .build();
Tracer tracer = tracerProvider.get("mon-service");
Span span = tracer.spanBuilder("mon-operation").startSpan(); // Votre code span.end(); }}Option 2 : Auto-instrumentation (zéro code)
Section intitulée « Option 2 : Auto-instrumentation (zéro code) »Pour les frameworks populaires, OpenTelemetry peut instrumenter automatiquement sans modifier le code.
pip install opentelemetry-distro opentelemetry-exporter-otlpopentelemetry-bootstrap -a install# Lancer votre app avec auto-instrumentationOTEL_SERVICE_NAME=mon-service \OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4317 \opentelemetry-instrument python app.py# Télécharger l'agentcurl -LO https://github.com/open-telemetry/opentelemetry-java-instrumentation/releases/latest/download/opentelemetry-javaagent.jar# Lancer avec l'agentjava -javaagent:opentelemetry-javaagent.jar \ -Dotel.service.name=mon-service \ -Dotel.exporter.otlp.endpoint=http://localhost:4317 \ -jar mon-app.jarnpm install @opentelemetry/auto-instrumentations-node# Lancer avec auto-instrumentationOTEL_SERVICE_NAME=mon-service \OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4317 \node --require @opentelemetry/auto-instrumentations-node/register app.jsOption 3 : Variables d'environnement (Kubernetes)
Section intitulée « Option 3 : Variables d'environnement (Kubernetes) »Sur Kubernetes, configurez les pods avec des variables d'environnement :
apiVersion: apps/v1kind: Deploymentmetadata: name: mon-servicespec: template: spec: containers: - name: app image: mon-image env: - name: OTEL_SERVICE_NAME value: "mon-service" - name: OTEL_EXPORTER_OTLP_ENDPOINT value: "http://otel-collector.observability.svc:4317" - name: OTEL_TRACES_EXPORTER value: "otlp"Validation : vérifier que ça fonctionne
Section intitulée « Validation : vérifier que ça fonctionne »-
Vérifiez les logs du Collector
Fenêtre de terminal docker logs otel-collector --tail 50Si des traces arrivent, vous verrez :
2026-02-09T10:05:00.000Z info TracesExporter {"kind": "exporter", "data_type": "traces", "name": "otlp/jaeger", "spans": 5} -
Vérifiez dans Jaeger
Ouvrez http://localhost:16686
- Sélectionnez le service dans le menu déroulant
- Cliquez sur "Find Traces"
- Vous devez voir vos traces
-
Générez du trafic de test
Si vous n'avez pas encore d'application instrumentée, utilisez
telemetrygen:Fenêtre de terminal docker run --rm --network observability \ghcr.io/open-telemetry/opentelemetry-collector-contrib/telemetrygen:0.145.0 \traces --otlp-insecure --otlp-endpoint otel-collector:4317Cette commande génère 1 trace de test. Vérifiez qu'elle apparaît dans Jaeger.
Pipeline complet : métriques, logs et traces
Section intitulée « Pipeline complet : métriques, logs et traces »Voici une configuration complète pour les trois types de signaux :
receivers: otlp: protocols: grpc: endpoint: 0.0.0.0:4317 http: endpoint: 0.0.0.0:4318
# Scraper les métriques Prometheus des apps prometheus: config: scrape_configs: - job_name: 'applications' scrape_interval: 30s static_configs: - targets: ['app1:8080', 'app2:8080']
processors: memory_limiter: check_interval: 1s limit_mib: 512 spike_limit_mib: 128 batch: timeout: 5s send_batch_size: 1000 # Ajouter des attributs à toutes les données resource: attributes: - key: environment value: production action: insert
exporters: # Traces vers Tempo otlp/tempo: endpoint: tempo:4317 tls: insecure: true
# Métriques vers Mimir (compatible remote write) prometheusremotewrite: endpoint: http://mimir:9009/api/v1/push
# Logs vers Loki loki: endpoint: http://loki:3100/loki/api/v1/push labels: resource: service.name: "service_name"
debug: verbosity: basic
extensions: health_check: endpoint: 0.0.0.0:13133 zpages: endpoint: 0.0.0.0:55679
service: extensions: [health_check, zpages] pipelines: traces: receivers: [otlp] processors: [memory_limiter, resource, batch] exporters: [otlp/tempo, debug]
metrics: receivers: [otlp, prometheus] processors: [memory_limiter, resource, batch] exporters: [prometheusremotewrite]
logs: receivers: [otlp] processors: [memory_limiter, resource, batch] exporters: [loki]Dépannage
Section intitulée « Dépannage »| Symptôme | Cause probable | Solution |
|---|---|---|
connection refused | Collector ne tourne pas ou mauvais endpoint | docker ps + vérifiez l'URL |
| Pas de traces dans Jaeger | Exporter mal configuré | Vérifiez les logs du Collector |
| Traces dans logs mais pas dans backend | Backend injoignable | Testez la connexion : curl backend:port |
| OOM du Collector | Pas de memory_limiter | Ajoutez le processor en premier |
| Données perdues | Batch trop gros ou timeout trop court | Réduisez send_batch_size |
| Health check échoue | Collector crashé ou mal démarré | docker logs otel-collector |
| zpages inaccessible | Extension non activée ou mauvais port | Vérifiez service.extensions |
Commandes de diagnostic
Section intitulée « Commandes de diagnostic »# État du collectordocker ps | grep otel-collector
# Health checkcurl http://localhost:13133/
# Logs récentsdocker logs otel-collector --tail 100
# Valider la configurationdocker exec otel-collector otelcol-contrib validate --config /etc/otelcol-contrib/config.yaml
# Debug des pipelines (zpages)curl http://localhost:55679/debug/pipelinezcurl http://localhost:55679/debug/servicezcurl http://localhost:55679/debug/tracezChecklist production
Section intitulée « Checklist production »Avant de passer en production, validez ces points :
- Version pinnée : pas de
:latest, utilisez0.145.0ou supérieur - Pas de conflit de ports : Jaeger et Collector sur le même réseau Docker
- health_check activé :
curl localhost:13133/retourne OK - memory_limiter configuré : évite les OOM
- debug exporter retiré : ou passé en
verbosity: basic - OTEL_EXPORTER_OTLP_PROTOCOL défini : évite les surprises gRPC/HTTP
- Bind localhost en dev :
-p 127.0.0.1:4317:4317 - Labels Loki maîtrisés : faible cardinalité (service, namespace, level)
- Kubernetes : choix clair entre DaemonSet (agent) et Deployment (gateway)
À retenir
Section intitulée « À retenir »- Le Collector est un intermédiaire entre vos apps et vos backends
- Architecture Receiver → Processor → Exporter pour chaque pipeline
- Utilisez toujours
memory_limiteretbatch(dans cet ordre) - Activez
health_checketzpagespour le diagnostic - Vos apps envoient en OTLP : port 4317 (gRPC) ou 4318 (HTTP)
- Pinnez les versions en production, évitez
:latest - Changez de backend en modifiant la config, pas le code