Observabilité de Bout en Bout : Tracing Distribué avec OpenTelemetry
Instrumenter Next.js, les pilotes SQL et les microservices avec propagation de contexte W3C.
1. Propagation d’en-têtes de trace W3C
Une trace distribuée ne vaut que ce que vaut sa propagation — chaque service du chemin d’une requête doit s’accorder sur la façon dont l’identité d’une trace circule à travers les frontières réseau, faute de quoi vous obtenez des fragments déconnectés plutôt qu’une image cohérente unique. La spécification W3C Trace Context standardise cela sous forme d’en-tête `traceparent` : une chaîne au format fixe encodant une version, un identifiant de trace de 16 octets partagé par tous les spans de la requête, un identifiant de span parent de 8 octets identifiant l’appelant immédiat, et des flags de trace indiquant si cette trace est échantillonnée.
Avant l’existence de cette norme, chaque fournisseur (les en-têtes B3 de Zipkin, le format propre de Jaeger, le format d’AWS X-Ray) utilisait des en-têtes de propagation incompatibles, ce qui signifiait qu’une requête passant d’un service instrumenté avec le SDK d’un fournisseur à un service instrumenté avec celui d’un autre cassait silencieusement la trace en deux traces sans lien. Les SDK d’OpenTelemetry implémentent le W3C Trace Context par défaut, et pratiquement tous les backends d’observabilité (Datadog, Honeycomb, Grafana Tempo, AWS X-Ray via un adaptateur) le comprennent désormais, ce qui fait d’OpenTelemetry une véritable couche d’instrumentation neutre vis-à-vis des fournisseurs, plutôt qu’un format propriétaire de plus auquel s’enfermer.
En pratique, la propagation est en grande partie automatique dès lors que vous instrumentez correctement vos bibliothèques client et serveur HTTP — l’auto-instrumentation du SDK OpenTelemetry pour `fetch`, `http` et les frameworks courants injecte et extrait l’en-tête de façon transparente. L’endroit où cela casse, ce sont les frontières asynchrones que le SDK ne peut pas voir automatiquement : files de messages, systèmes de jobs en arrière-plan et webhooks, où vous devez propager manuellement le contexte de trace en le sérialisant dans le payload du message et en le réextrayant côté consommateur.
2. Corrélation des logs structurés et des traces
Les traces indiquent où le temps a été consommé ; les logs indiquent ce qui s’est réellement passé à un point précis. Ensemble, ils deviennent nettement plus utiles que séparément, mais seulement si chaque ligne de log émise pendant une requête porte l’identifiant de trace et de span de cette requête, ce qui permet de basculer d’un span lent dans votre interface de tracing directement vers les lignes de log exactes émises durant ce span, au lieu de grepper des timestamps en espérant qu’ils correspondent.
Cela exige des logs structurés (JSON) plutôt que du texte libre, car il faut des champs interrogeables par machine (`trace_id`, `span_id`) attachés à chaque entrée, et cela exige de brancher votre logger sur la lecture du contexte OpenTelemetry actif au moment du log — la plupart des bibliothèques de logging (Pino, Winston, structlog) disposent d’une intégration OpenTelemetry ou d’un petit middleware qui injecte automatiquement ces champs depuis le contexte de span actif, sans que le code applicatif n’ait à faire circuler les identifiants de trace manuellement.

