ITSkillsCenter
Business Digital

Envoyer les traces vers Tempo pas-a-pas

10 دقائق للقراءة

📍 Article principal : Observabilité applicative en 2026 : OpenTelemetry, traces distribuées et stack LGTM — pour le contexte conceptuel et l’architecture d’ensemble.

Pourquoi envoyer les traces vers Tempo

Tempo est le backend de tracing distribué de la stack Grafana. Il occupe une niche très claire dans l’écosystème : stocker des traces à très grande échelle, sur stockage objet, sans index recherchable au sens classique. Cette absence d’index est délibérée — c’est elle qui permet à Tempo d’avaler des volumes que les backends de tracing historiques ne tenaient pas, à un coût d’infrastructure dramatiquement plus bas. La contrepartie est qu’on ne « cherche » pas dans Tempo comme on cherche dans Elasticsearch ; on consulte une trace par son trace_id et on filtre des spans avec TraceQL.

Tempo ingère OTLP nativement, en gRPC ou HTTP, et s’intègre profondément à Grafana pour la corrélation logs-traces et métriques-traces. Ce tutoriel construit la pipeline d’envoi pas-à-pas, explique le format de stockage, et montre comment requêter en TraceQL.

Prérequis

  • Une instance Tempo joignable (Docker, binaire ou Kubernetes)
  • Un OpenTelemetry Collector configuré — voir le tutoriel Configurer un OpenTelemetry Collector
  • Une application instrumentée qui produit des traces OTLP
  • Une instance Grafana pour la visualisation
  • Temps estimé : 30 à 45 minutes

Étape 1 — Vérifier l’écoute OTLP de Tempo

Tempo expose deux receivers OTLP par défaut : gRPC sur le port 4317 et HTTP sur le port 4318, exactement les ports standardisés. Avant de configurer le Collector, on s’assure que Tempo écoute bien et qu’il est ready.

# statut general
curl http://127.0.0.1:3200/ready
curl http://127.0.0.1:3200/status

# version embarquée
curl http://127.0.0.1:3200/api/status/buildinfo

Si /ready retourne ready, Tempo accepte du trafic. Le port 3200 est l’API HTTP de Tempo (requêtes, status). Les ports 4317 et 4318 sont les receivers OTLP. Une erreur fréquente est de pointer le Collector vers le port API au lieu du port OTLP — vérifier la cohérence.

Étape 2 — Configurer Tempo en réception OTLP

La configuration de Tempo dédiée à OTLP tient en quelques lignes. On déclare le distributor avec les receivers OTLP activés, puis on laisse les valeurs par défaut pour les autres composants.

# tempo.yaml (extrait minimal)
server:
  http_listen_port: 3200

distributor:
  receivers:
    otlp:
      protocols:
        grpc:
          endpoint: 0.0.0.0:4317
        http:
          endpoint: 0.0.0.0:4318

ingester:
  trace_idle_period: 10s
  max_block_duration: 5m

storage:
  trace:
    backend: local
    local:
      path: /var/tempo/traces
    wal:
      path: /var/tempo/wal

Pour un environnement de développement, le backend local écrit sur disque local. En production, on remplace par s3 ou gcs avec le stockage objet correspondant. Le trace_idle_period définit combien de temps un span peut rester en attente avant d’être considéré comme appartenant à une trace en cours. La valeur par défaut côté Tempo est 5 secondes ; on la monte couramment à 10 secondes pour couvrir des requêtes web légèrement plus longues.

Étape 3 — Configurer l’exporter Tempo côté Collector

Côté Collector, on utilise l’exporter OTLP gRPC standard pour la performance. Tempo ne nécessite pas d’exporter spécifique « tempo » — c’est un consommateur OTLP comme un autre.

# otelcol.yaml (extension)
exporters:
  otlp/tempo:
    endpoint: tempo:4317
    tls:
      insecure: true
    sending_queue:
      enabled: true
      num_consumers: 4
      queue_size: 5000
    retry_on_failure:
      enabled: true
      initial_interval: 5s
      max_interval: 30s
      max_elapsed_time: 300s

service:
  pipelines:
    traces:
      receivers: [otlp]
      processors: [memory_limiter, resource, batch]
      exporters: [otlp/tempo]

Les sections sending_queue et retry_on_failure ne sont pas optionnelles en production. La queue absorbe les pics de débit ; le retry assure qu’une coupure réseau temporaire ne fait pas perdre les données. Sans ces sécurités, un redémarrage de Tempo de 30 secondes peut faire perdre la fenêtre de traces correspondante.

Étape 4 — Vérifier l’arrivée des spans

On déclenche du trafic depuis l’application instrumentée et on consulte Tempo via Grafana ou directement via son API. La voie la plus simple est d’ouvrir Grafana Explore avec le datasource Tempo et de chercher par service.

# API Tempo : recherche TraceQL
curl -G "http://127.0.0.1:3200/api/search" \
  --data-urlencode 'q={resource.service.name="otel-go-demo"}' \
  --data-urlencode 'limit=10' | jq

La réponse JSON contient les traceID récents avec leurs métadonnées. Pour ouvrir une trace complète :

curl http://127.0.0.1:3200/api/traces/<TRACE_ID> | jq

L’arbre complet apparaît avec tous les spans, leurs attributs et leur chronologie. Si la trace ne sort pas, vérifier que le trace_idle_period est dépassé (par défaut 10 secondes) — Tempo retient la trace en mémoire tant qu’il pense qu’elle peut s’enrichir de nouveaux spans.

Étape 5 — Premiers pas avec TraceQL

TraceQL est le langage de requête de Tempo. Sa syntaxe est conçue pour exprimer des conditions sur des spans à l’intérieur d’une trace. La famille de sélecteurs principaux est {} avec des prédicats sur les attributs de span ou de resource.

# traces du service spécifique
{ resource.service.name="otel-go-demo" }

# traces qui contiennent un span en erreur
{ status = error }

# traces où une route HTTP a duré plus de 500 ms
{ name = "GET /score/:id" && duration > 500ms }

# traces avec un attribut métier précis
{ span.user.id = "u-42" }

# combinaison : traces erreur du service spécifique sur 1 heure
{ resource.service.name = "otel-python-demo" && status = error }

L’utilisation de TraceQL change la philosophie d’investigation : au lieu de chercher en plein texte comme dans un log, on filtre par condition structurée sur les spans, ce qui est plus rapide et plus précis. Pour des analyses agrégées (taux d’erreur par service, latence p99 par opération), on combine TraceQL avec la fonctionnalité span metrics qui transforme les traces en métriques exposables côté Mimir.

Étape 6 — Configurer le datasource Grafana

Côté Grafana, on configure le datasource Tempo pour pointer sur l’API Tempo et activer les liens utiles entre signaux.

# grafana datasource Tempo — provisioning
apiVersion: 1
datasources:
  - name: Tempo
    type: tempo
    uid: tempo
    url: http://tempo:3200
    jsonData:
      tracesToLogsV2:
        datasourceUid: loki
        spanStartTimeShift: '-1m'
        spanEndTimeShift: '1m'
        tags:
          - { key: service.name, value: service_name }
        filterByTraceID: true
        filterBySpanID: false
      tracesToMetrics:
        datasourceUid: mimir
        tags:
          - { key: service.name, value: service }
      serviceMap:
        datasourceUid: mimir
      nodeGraph:
        enabled: true
      lokiSearch:
        datasourceUid: loki

Trois sections importantes : tracesToLogsV2 permet depuis une trace dans Tempo de sauter aux logs de la même requête dans Loki, en filtrant par trace_id. tracesToMetrics permet de sauter d’un span vers les métriques RED (Rate, Errors, Duration) du service correspondant dans Mimir. serviceMap active la carte de dépendances inter-services générée à partir des traces. Le détail de ces corrélations est creusé dans le tutoriel Corréler trace_id entre logs, métriques et traces dans Grafana.

Étape 7 — Span metrics : transformer les traces en métriques

Une fonctionnalité puissante de Tempo est de générer automatiquement des métriques à partir des traces ingérées. Les span metrics exposent en sortie un nombre fixe de séries Prometheus (taux, erreurs, durée par service et par opération) qui alimentent les dashboards SRE classiques sans devoir instrumenter les métriques côté application.

# tempo.yaml (extension)
metrics_generator:
  registry:
    external_labels:
      source: tempo
      cluster: eu-west-1
  storage:
    path: /var/tempo/generator/wal
    remote_write:
      - url: http://mimir:9009/api/v1/push

overrides:
  defaults:
    metrics_generator:
      processors: [service-graphs, span-metrics]
      collection_interval: 15s

Avec cette configuration, Tempo génère et envoie vers Mimir des métriques telles que traces_spanmetrics_calls_total (Counter), traces_spanmetrics_latency_bucket (Histogram, ex traces_spanmetrics_duration_seconds avant Tempo 1.5), et traces_service_graph_request_total. Ces métriques alimentent automatiquement les dashboards RED par service sans que l’application ait à compter elle-même.

Étape 8 — Vérifier la corrélation logs ↔ traces

Test final : depuis une trace dans Grafana, ouvrir Loki via le bouton « Logs for this span » et voir les logs émis pendant la trace. Cette navigation bidirectionnelle est la valeur diagnostique la plus immédiate de la stack LGTM. Si la corrélation ne fonctionne pas, vérifier dans cet ordre : présence du trace_id dans les logs (structured metadata côté Loki), datasource tracesToLogsV2 bien configuré, et alignement des labels mappés (service.name côté Tempo, service_name côté Loki).

Erreurs fréquentes

Pointer vers le port API au lieu du port OTLP

Tempo écoute sur 3200 (API) et 4317/4318 (OTLP). Configurer l’exporter du Collector vers tempo:3200 produit des erreurs de désérialisation. La cible OTLP est tempo:4317 en gRPC.

Trace incomplète à cause d’un span jamais clôturé

Si l’application oublie span.end() ou span.End() pour un span donné, Tempo ne reçoit qu’une partie de l’arbre, et la trace apparaît tronquée ou incohérente. Le diagnostic se fait côté SDK (logs en debug) ou via l’absence de spans attendus dans Tempo.

Backend de stockage local en production

Le backend local est conçu pour le dev. En production, le stockage local sature rapidement et un redémarrage perd les blocs en cours. Toujours utiliser S3, GCS ou Azure Blob avec une rétention adaptée (souvent 30 jours pour les traces, contre 90 jours pour les logs).

Sampling à 1 % côté SDK puis investigation impossible

Le sampling head-based à l’application coupe à l’aveugle 99 % des traces, y compris celles en erreur. Tempo accepte un volume élevé, profitons-en : 100 % côté SDK, sampling tail-based dans le Collector si le coût justifie la réduction. Voir Tail-based sampling pour maîtriser les coûts.

Confondre l’index et l’absence d’index

Tempo n’indexe pas le corps des spans comme Elasticsearch indexe le corps d’un document. Les requêtes TraceQL filtrent les blocs ramenés depuis le stockage. Pour des recherches fréquentes par attribut métier, configurer les local-blocks et envisager un préfiltrage en amont via les attributs de resource (qui sont indexés sous forme de service stats).

Tutoriels associés

Ressources et références officielles

FAQ

Tempo vs Jaeger ?

Jaeger reste pertinent pour des déploiements existants ou des cas où l’on veut un index plus riche. Tempo a l’avantage du stockage objet économique et de l’intégration native Grafana. À volume élevé, Tempo gagne presque toujours sur le coût.

Quelle rétention typique pour les traces ?

Souvent 7 à 30 jours. Au-delà, les traces deviennent peu utiles pour l’investigation et le coût stockage devient sensible même sur S3. Pour une analyse à plus long terme, on s’appuie sur les span metrics agrégées dans Mimir, qui restent à coût modéré sur des années.

Tempo accepte-t-il Jaeger ou Zipkin en réception ?

Oui, le distributor de Tempo a des receivers compatibles Jaeger (Thrift compact, gRPC) et Zipkin. C’est utile pour migrer progressivement depuis ces stacks sans recoder l’instrumentation. La voie OTLP reste recommandée pour de nouveaux services.

Comment dimensionner Tempo ?

Une instance modeste absorbe quelques milliers de spans par seconde. À grande échelle, déploiement microservices avec distributor, ingester, querier séparés — la doc Grafana Tempo détaille le dimensionnement par profil de charge.

Le service map est-il pertinent en production ?

Très utile pour la cartographie d’architecture et la détection des dépendances inattendues. Le générateur de service-graph côté Tempo produit ces graphes à partir des traces sans instrumentation supplémentaire — une fonctionnalité différenciante par rapport à des backends de tracing plus anciens.

Sponsoriser ce contenu

Cet emplacement est à vous

Position premium en fin d'article — c'est l'instant où les lecteurs sont le plus engagés. Réservez cet espace pour votre marque, votre formation ou votre offre.

Recevoir nos tarifs
Publicité