Un service produit des logs dans plusieurs formats, des métriques dans un outil séparé, et rien ne relie une requête lente à l’appel qui l’a provoquée. Pour comprendre un incident, il faut recouper ces sources à la main.
OpenTelemetry répond à ce problème. Il fournit un format standard dans lequel le code décrit ce qu’il fait. Un humain ou un agent exploite ensuite cette télémétrie.
Cet article ouvre une série sur la mise en pratique de l’observabilité, issue d’un retour d’expérience personnel :
- on installera ensuite une stack auto-hébergée (OpenObserve sur un cluster Scaleway Kapsule),
- on instrumentera trois services en Go, Rust et Java,
- puis, on rendra cette télémétrie interrogeable par une CLI
- enfin, on automatisera l’exploitation de l’observabilité à l’aide d’un agent Claude Code.
Ce premier article pose le vocabulaire commun.
Monitoring et observabilité : questions prévues et questions imprévues
Le monitoring surveille des indicateurs qu’on a choisis à l’avance : CPU, latence p99, taux d’erreur. Il répond bien aux questions qu’on savait poser, les « known unknowns ».
L’observabilité permet de répondre à une question qu’on n’avait pas anticipée, en explorant les données déjà collectées. Ce sont les « unknown unknowns » : pourquoi ce client précis a des timeouts depuis 14h32, alors qu’aucune alerte ne s’est déclenchée.
La page sur les concepts d’OpenTelemetry détaille cette distinction[3].
OpenTelemetry, contrat d’interface entre le code et le backend
OpenTelemetry est le contrat d’interface entre le code et n’importe quel backend. Le code appelle l’API OpenTelemetry et émet sa télémétrie en OTLP. Un Collector OpenTelemetry la reçoit, puis l’exporte vers le backend.
Les logs suivent ce chemin comme les métriques et les traces. Le SDK les envoie au Collector, ou le Collector les lit lui-même (voir la section sur les logs).
Le backend qui reçoit la télémétrie (OpenObserve dans cette série) n’impose pas sa convention de nommage au code. Dans un prochain article, nous développerons trois services dans trois langages qui partageront ainsi un format de log commun.
Logs, métriques, traces et corrélation par trace_id
OpenTelemetry structure la télémétrie en trois signaux :
- les logs sont des événements horodatés, structurés ou non ;
- les métriques sont des séries numériques agrégées dans le temps : compteurs, jauges, histogrammes ;
- les traces forment l’arbre des spans qui représente le parcours d’une requête à travers plusieurs services.
Un quatrième signal, les profiles (profilage continu de CPU et de mémoire), est en statut Development pour l’export OTLP[1].
Les trois signaux sont corrélés par un trace_id et un span_id, qui situent la donnée dans une requête, et par une resource, qui identifie son origine (service.name, service.namespace, service.version, deployment.environment.name).
Ces quatre attributs de resource sont un choix de nommage fait dans un prochain article.
Ils sont posés une fois pour les trois services de la démo, qui héritent partout des mêmes valeurs.
Le trace_id identifie une requête de bout en bout. C’est un identifiant de 16 octets (32 caractères hexadécimaux), généré au premier service qui reçoit la requête et partagé par tous les spans de la trace, quel que soit le service qui les produit[4][11].
Le span_id identifie une opération précise au sein de cette trace : un appel HTTP, une requête SQL, un traitement interne. C’est un identifiant de 8 octets (16 caractères hexadécimaux), propre à chaque span. Chaque span référence le span_id de son parent, ce qui reconstitue l’arbre des appels[15].
Un log émis pendant un span porte le trace_id et le span_id de ce span. Depuis un log, on retrouve ainsi la trace complète et l’opération exacte qui l’a produit[12].
trace_id. Chacun a son span_id et référence celui de son parent. Le log émis dans reserve-stock porte les deux identifiants.Deux chemins pour envoyer les logs au Collector
Les logs arrivent au Collector de deux façons :
- l’application les émet en OTLP : les SDK fournissent un pont (log bridge) vers les bibliothèques de logging existantes (
slogen Go,tracingen Rust, Logback ou Log4j en Java), et les logs partent avec letrace_idet la resource de l’application ; - l’application continue d’écrire dans un fichier ou sur la sortie standard, et le Collector les lit avec un receiver comme
filelog, avant de les convertir au modèle de données OpenTelemetry.
Dans les deux cas, le Collector applique ses processors puis les exporte vers le backend. Le format de log n’est plus propre à l’outil de stockage.
otlp. Sans lui, le receiver filelog lit le fichier ou la sortie standard. Les deux flux passent ensuite par les mêmes processors et le même exporter.Propagation du contexte de trace avec l’en-tête traceparent
Pour que les spans de trois services différents forment une seule trace, il faut propager un contexte d’un service à l’autre. C’est le rôle du standard W3C Trace Context, avec son en-tête HTTP traceparent[4] :
traceparent: 00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01
Quatre champs séparés par des tirets : la version, le trace-id (16 octets, partagé par toute la trace), le parent-id (8 octets, le span courant) et des flags (ici, échantillonné).
À côté de traceparent, l’en-tête baggage transporte des paires clé-valeur métier (un user.id, un tenant) tout au long de la requête, indépendamment des spans. Baggage est stable dans la spécification OpenTelemetry, pour l’API comme pour le SDK[1].
La propagation relève du transport HTTP (ou gRPC, ou message broker). Un SDK OTel configuré injecte et extrait cet en-tête. Le code applicatif n’a pas à le manipuler.
On verra la mécanique concrète Go → Rust → Java dans l’article sur l’instrumentation des trois services.
traceparent à l’appel suivant. Le trace-id ne change pas. Le parent-id porte le span_id du span appelant. Les trois spans arrivent séparément au Collector, et le backend les regroupe par trace_id.L’architecture : API, SDK, instrumentation, Collector, OTLP
OpenTelemetry sépare cinq couches.
L’API est l’ensemble des interfaces que le code applicatif appelle pour créer un span ou incrémenter un compteur. Elle est stable et indépendante de l’implémentation. Le SDK fait le travail concret : échantillonnage, traitement par lots, export.
Sa maturité dépend du langage (voir le tableau plus bas).
L’instrumentation est le code qui produit réellement de la télémétrie à partir de l’application, en zero-code (agent Java, auto-instrumentation) ou à la main (appels explicites à l’API). Le Collector, enfin, est un processus séparé qui reçoit la télémétrie (receivers), la transforme (processors) et la réexpédie (exporters) vers un ou plusieurs backends, selon des pipelines déclarés en configuration.
Le transport entre ces couches, c’est OTLP (OpenTelemetry Protocol), en gRPC (port 4317) ou en HTTP (port 4318). Dans cette série, les applications parleront OTLP/HTTP au Collector, qui relaiera ensuite vers OpenObserve en otlphttp. On détaillera ce montage dans l’article sur l’installation du Collector.
receivers → processors → exporters relaie la télémétrie vers OpenObserve.Le processor batch regroupe la télémétrie avant export. Il est en statut bêta et présent dans toutes les distributions du Collector[9]. Une migration vers un batching intégré aux exporters (sending_queue.batch) est en cours, avec un queuebatchprocessor encore en développement[9][10].
Statut de stabilité de la spécification et des SDK
La spécification est stable pour les traces et les logs, ainsi que pour Baggage, le mécanisme de propagation de paires clé-valeur métier décrit plus haut. Pour les métriques, l’API et le protocole sont stables[1]. Le statut des SDK dépend ensuite du langage.
| Signal (spec) | Statut spec | Go | Rust | Java |
|---|---|---|---|---|
| Traces | Stable | Stable | Bêta | Stable |
| Métriques | API stable, SDK mixed | Stable | Stable | Stable |
| Logs | Stable | Stable | Stable | Stable |
| Profiles | Development | — | — | — |
Sources : statut de la spécification[1], notes de version d’OpenTelemetry Go v1.47.0[13] et README d’OpenTelemetry Rust[14], au 8 octobre 2026.
Java et Go sont stables pour les trois signaux. Les logs de Go sont stables depuis la version 1.47.0, publiée le 2 octobre 2026[13]. Rust est stable pour les métriques et les logs, et en bêta pour les traces[14]. La page de statut par langage du site OpenTelemetry[2] indiquait encore, le 8 octobre 2026, une release candidate pour les logs Go et une bêta pour les trois signaux en Rust.
Le choix des versions est détaillé dans l’article sur l’instrumentation des trois services.
Conventions sémantiques et format d’échange
Les conventions sémantiques[5] définissent les noms d’attributs standard, comme http.request.method ou db.system.name.
Elles ne sont pas toutes au même stade :
- HTTP est stable depuis 2023[6],
- les bases de données ont un chemin de migration documenté[7],
- les attributs Kubernetes sont en release candidate[8],
- et les conventions liées aux agents et aux LLM (GenAI) sont encore en développement actif.
On y reviendra en détail dans le dernier article de la série, consacré à l’observation de Claude Code lui-même.
Ressources
- Statut de la spécification OpenTelemetry
- Statut par langage
- Observability primer
- W3C Trace Context
- Conventions sémantiques v1.44.0
- Conventions HTTP stables depuis 2023
- Migration des conventions DB
- Conventions Kubernetes en release candidate
- README du batch processor
- Pourquoi le batch processor va évoluer
- Spécification de l’API Trace : TraceId et SpanId
- Modèle de données des logs : TraceId et SpanId
- OpenTelemetry Go v1.47.0 : première version stable des logs
- OpenTelemetry Rust : statut du projet
- Trace ID et Span ID dans OpenTelemetry (SigNoz)
