Aller au contenu
Culture DevOps high
🚧 Section en cours de réécriture — Le contenu est en cours de restructuration et peut évoluer.

Observabilité : logs, métriques et traces

18 min de lecture

Il est 3h du matin. Votre téléphone sonne. Un client VIP signale que ses paiements échouent depuis une heure. Vous ouvrez vos dashboards : CPU normal, mémoire normale, taux d’erreur global à 0.3%. Tout semble vert. Pourtant, quelque chose ne va pas.

Vous passez les deux heures suivantes à fouiller dans les logs de six services différents, à deviner quel appel a échoué, à reconstituer le parcours de la requête comme un archéologue recolle les tessons d’une poterie brisée. À 5h du matin, vous trouvez enfin : un timeout sur l’API bancaire, déclenché uniquement pour les montants supérieurs à 500€ — parce qu’un contrôle anti-fraude externe était en panne.

Ce scénario illustre parfaitement la différence entre monitoring et observabilité. Votre monitoring vous disait que tout allait bien. Mais votre système n’était pas observable — vous ne pouviez pas comprendre son comportement réel en analysant ses sorties.

Monitoring vs Observabilité : deux approches différentes

Section intitulée « Monitoring vs Observabilité : deux approches différentes »

Ces deux termes sont souvent confondus ou utilisés comme synonymes. Ils désignent pourtant des approches fondamentalement différentes face aux systèmes complexes.

AspectMonitoringObservabilité
Question”Est-ce que X dépasse le seuil Y ?""Pourquoi le système se comporte-t-il ainsi ?”
ApprocheQuestions prédéfiniesQuestions ad-hoc, exploration
ForceDétecter les problèmes connusDiagnostiquer les problèmes inconnus
LimiteNe voit que ce qu’on lui demandeNécessite instrumentation riche
AnalogieVoyants du tableau de bordDiagnostic OBD complet

Le monitoring traditionnel fonctionne sur un principe simple : vous décidez à l’avance ce que vous voulez surveiller, vous posez des seuils, et vous êtes alerté quand ces seuils sont dépassés. C’est une approche par questions prédéfinies.

Quand vous configurez une alerte “CPU > 90%”, vous demandez au système de répondre à une question que vous avez formulée en amont : “Est-ce que le CPU dépasse 90% ?”. Le monitoring excelle pour détecter les problèmes connus — ceux que vous avez anticipés et pour lesquels vous avez prévu des seuils.

Mais le monitoring atteint ses limites face à l’inattendu. Quand un utilisateur dit “c’est lent” et que tous vos indicateurs sont au vert, le monitoring ne vous aide pas. Il ne sait répondre qu’aux questions que vous lui avez apprises.

L’observabilité permet de poser des questions nouvelles

Section intitulée « L’observabilité permet de poser des questions nouvelles »

L’observabilité répond à une question différente : “Pourquoi le système se comporte-t-il ainsi ?”. Un système est observable si vous pouvez comprendre son état interne simplement en analysant ce qu’il produit — ses sorties — sans avoir besoin de modifier son code ni de le redéployer.

Le terme vient de la théorie du contrôle : un système est “observable” si son état interne peut être déduit de ses sorties externes. En ingénierie logicielle, cela se traduit par la capacité à investiguer des problèmes que vous n’aviez pas anticipés.

Reprenons le scénario d’ouverture. Avec un système observable, vous auriez pu partir du symptôme utilisateur (“paiements échoués pour ce client”), filtrer les traces de ce client spécifique, voir immédiatement quel service posait problème, puis plonger dans les logs de ce service pour comprendre la cause. Au lieu de deux heures de fouille archéologique, quelques minutes d’investigation structurée.

L’observabilité moderne repose sur trois types de données complémentaires. Chacun apporte une perspective différente sur le comportement du système, et c’est leur combinaison qui permet une compréhension complète.

PilierRôleForceFaiblesse
LogsRécit détaillé des événementsDebugging, audit, conformitéVolume énorme, coût de stockage
MétriquesVue d’ensemble agrégéeTendances, alertes, dashboardsPas de détail individuel
TracesParcours d’une requêteIdentifier les goulots, dépendancesComplexité d’implémentation

Les 3 piliers de l'observabilité : logs, métriques et traces, reliés par la corrélation via trace_id

Les logs sont des enregistrements d’événements horodatés. Ils racontent ce qui s’est passé dans le système, événement par événement, comme un journal de bord.

Un log bien structuré ressemble à ceci :

{
"timestamp": "2026-01-10T14:32:15.123Z",
"level": "ERROR",
"service": "payment-api",
"trace_id": "abc123",
"user_id": "usr_456",
"message": "Payment failed",
"error_code": "CARD_DECLINED",
"amount": 99.99,
"currency": "EUR"
}

Chaque champ apporte du contexte. Le timestamp vous dit quand. Le service vous dit . Le trace_id vous permet de relier ce log aux autres événements de la même requête. Les champs métier (amount, currency) vous donnent le contexte nécessaire pour comprendre l’impact.

Les logs brillent pour le debugging détaillé. Quand vous savez qu’il y a un problème quelque part, les logs vous racontent l’histoire complète de ce qui s’est passé. Ils sont également indispensables pour l’audit et la conformité — preuve de qui a fait quoi, et quand.

Mais les logs ont des faiblesses. Leur volume peut devenir énorme — une application moderne peut générer des gigaoctets de logs par jour. Leur coût de stockage explose rapidement. Et surtout, les logs bruts sont difficiles à agréger : “Combien d’erreurs de paiement avons-nous eu cette semaine ?” est une question pénible à répondre en parcourant des millions de lignes de texte.

Deuxième pilier : les Métriques, la vue d’ensemble

Section intitulée « Deuxième pilier : les Métriques, la vue d’ensemble »

Les métriques sont des mesures numériques agrégées dans le temps. Là où les logs racontent des histoires individuelles, les métriques donnent une vue d’ensemble : combien de requêtes, quel temps de réponse moyen, quel taux d’erreur.

Une métrique se présente généralement ainsi :

http_requests_total{service="payment-api", status="500"} 142
http_request_duration_seconds{service="payment-api", quantile="0.99"} 2.3

Le premier exemple compte le nombre total de requêtes ayant retourné un code 500. Le second mesure le temps de réponse au 99e percentile — 2.3 secondes signifie que 99% des requêtes sont traitées en moins de 2.3 secondes.

Les métriques existent en trois grandes familles. Les counters ne font qu’augmenter : requêtes totales, erreurs cumulées, octets transférés. Les gauges montent et descendent : mémoire utilisée, connexions actives, température. Les histogrammes capturent la distribution : ils permettent de calculer percentiles et moyennes.

Les métriques brillent pour les tendances et les alertes. “Le taux d’erreur augmente-t-il ?” est une question triviale avec des métriques, impossible avec des logs seuls. Leur volume de données reste maîtrisé — quelques milliers de séries temporelles au lieu de millions de lignes de logs.

Mais les métriques ne racontent pas le pourquoi. Elles vous disent “5% d’erreurs” mais pas “pourquoi ces erreurs”. Et elles perdent le détail individuel — vous ne pouvez pas retrouver la requête spécifique qui a échoué pour un client donné.

Troisième pilier : les Traces, le chemin de la requête

Section intitulée « Troisième pilier : les Traces, le chemin de la requête »

Les traces suivent le parcours d’une requête à travers les différents services d’un système distribué. Dans une architecture microservices, une requête utilisateur peut traverser dix services avant de retourner une réponse. La trace capture ce voyage complet.

Une trace est composée de spans — chaque span représente une opération : un appel HTTP, une requête en base de données, un traitement interne. Voici à quoi ressemble une trace visualisée :

Trace: abc123 (durée totale: 850ms)
├── api-gateway (12ms)
│ └── auth-service (45ms)
├── payment-api (650ms) ← goulot d'étranglement
│ ├── fraud-check (120ms)
│ └── bank-api (480ms) ← appel externe lent
└── notification-service (35ms)

Cette vue est transformatrice. D’un coup d’œil, vous voyez que 650ms sur 850ms sont passées dans payment-api, dont 480ms dans l’appel à l’API bancaire. Le goulot d’étranglement saute aux yeux.

Les traces brillent pour identifier le temps se perd dans une architecture distribuée. Elles visualisent les dépendances entre services, souvent de manière surprenante — vous découvrez des appels dont vous ignoriez l’existence.

Mais les traces sont complexes à implémenter. Chaque service doit propager le contexte de trace au suivant. À grande échelle, l’échantillonnage devient nécessaire — vous ne pouvez pas stocker 100% des traces.

Chaque pilier seul a ses limites. Les métriques vous disent quoi mais pas pourquoi. Les logs vous disent pourquoi mais sont difficiles à naviguer. Les traces vous montrent mais pas le détail.

La vraie puissance de l’observabilité vient de la corrélation des trois piliers. Un identifiant unique — le trace_id — est généré à l’entrée de chaque requête et propagé à travers tous les services, tous les logs, toutes les métriques.

Imaginons un scénario concret. Votre alerte se déclenche : “Taux d’erreurs 500 > 5% sur payment-api”. C’est la métrique qui vous prévient qu’il y a un problème.

Vous ouvrez votre outil de traces et filtrez les requêtes en erreur des 15 dernières minutes. Vous remarquez que 80% d’entre elles ont un span bank-api qui timeout. C’est la trace qui vous montre est le problème.

Vous cliquez sur une trace spécifique et consultez les logs associés via le trace_id. Vous découvrez le message : “External API returned RATE_LIMIT_EXCEEDED”. C’est le log qui vous explique pourquoi.

En moins de cinq minutes, vous avez compris : un batch de réconciliation lancé par la finance a saturé les quotas de l’API bancaire. Vous suspendez le batch, les erreurs s’arrêtent.

Sans corrélation, vous auriez eu trois outils séparés avec trois vues partielles. Vous auriez passé une heure à reconstituer manuellement les liens entre l’alerte, les appels réseau, et les messages d’erreur.

Il existe un concept technique qui peut faire exploser vos coûts d’observabilité et dégrader vos performances : la cardinalité.

La cardinalité d’une métrique est le nombre de combinaisons uniques de labels possibles. Prenons un exemple simple. Une métrique avec un label service (5 valeurs) et un label status (5 valeurs) produit 25 séries temporelles. C’est une faible cardinalité, parfaitement gérable.

Maintenant, ajoutez un label user_id. Avec un million d’utilisateurs, vous passez à 5 × 5 × 1 000 000 = 25 millions de séries temporelles. Votre base de métriques passe de quelques gigaoctets à plusieurs téraoctets. Vos requêtes, qui prenaient millisecondes, prennent maintenant des minutes — ou échouent.

La règle est simple : n’utilisez jamais comme label une valeur à cardinalité illimitée. Les identifiants utilisateurs, les identifiants de requête, les sessions, les emails — tout ce qui peut prendre un nombre illimité de valeurs différentes — n’a pas sa place dans les labels de métriques.

Ces informations de haute cardinalité vont dans les logs, pas dans les métriques. Les logs sont conçus pour stocker des événements individuels avec des détails spécifiques. Les métriques sont conçues pour agréger.

Les labels à cardinalité maîtrisée incluent : service (dizaines), endpoint (centaines au maximum), status_code (une dizaine), region (dizaines), environment (quelques-uns). Chacun a un nombre fini et prévisible de valeurs.

Face à un nouveau système, par où commencer ? Trois frameworks éprouvés vous guident :

FrameworkCibleMétriquesQuand l’utiliser
REDServices (APIs)Rate, Errors, DurationMicroservices, endpoints utilisateur
USERessources (infra)Utilization, Saturation, ErrorsCPU, mémoire, disque, réseau
Golden SignalsServices critiquesLatency, Traffic, Errors, SaturationServices SRE, alerting production

Pour tout service orienté requêtes — une API, un microservice, un endpoint — mesurez trois choses. Le Rate : combien de requêtes par seconde. Les Errors : quel pourcentage échoue. La Duration : combien de temps prennent-elles.

Ces trois métriques suffisent à détecter la plupart des problèmes de service. Une chute du Rate peut indiquer un problème en amont. Une hausse des Errors signale une régression. Une hausse de la Duration prédit une saturation imminente.

Pour les ressources système — CPU, mémoire, disque, réseau — mesurez trois choses. L’Utilization : quel pourcentage de la capacité est utilisé. La Saturation : y a-t-il du travail en attente. Les Errors : y a-t-il des erreurs matérielles.

Un CPU à 75% d’utilisation avec une queue de scheduling vide est sain. Le même CPU avec une queue qui s’allonge est saturé, même si l’utilisation ne semble pas critique.

Google résume l’observabilité d’un service en quatre signaux essentiels. La Latency mesure le temps de réponse, en distinguant les requêtes réussies des erreurs — une erreur rapide n’a pas la même signification qu’une erreur après timeout. Le Traffic quantifie la demande sur le système, en requêtes par seconde. Les Errors comptent le taux d’échecs. La Saturation indique la marge de capacité restante avant que le système ne s’écroule.

Ces quatre métriques, bien implémentées, couvrent 90% des besoins d’alerting. Le reste est du raffinement.

Jusqu’à récemment, chaque outil d’observabilité avait ses propres formats, ses propres SDKs, ses propres protocoles. Passer de Jaeger à Zipkin, ou de Prometheus à Datadog, nécessitait de réinstrumenter tout le code.

OpenTelemetry (OTel) change la donne. C’est un projet open source de la CNCF qui unifie la collecte de logs, métriques et traces sous un même standard.

Le principe est simple : vous instrumentez votre code une fois avec le SDK OpenTelemetry, et vous pouvez ensuite envoyer les données vers n’importe quel backend compatible — Jaeger, Prometheus, Grafana, Datadog, New Relic, ou votre propre solution.

L’architecture typique comprend trois composants. L’application est instrumentée avec le SDK OTel, qui collecte les signaux. Le Collector centralise les données de plusieurs applications, les transforme si nécessaire, et les route vers une ou plusieurs destinations. Les backends stockent et permettent d’analyser les données.

Cette architecture de découplage est précieuse. Vous pouvez changer de backend sans toucher au code applicatif. Vous pouvez échantillonner ou filtrer les données dans le Collector. Vous pouvez envoyer les mêmes données vers plusieurs backends pour des usages différents.

L’observabilité n’est pas un projet qu’on installe une fois. C’est une discipline qui s’intègre au développement quotidien.

Pour les logs, adoptez un format structuré (JSON) avec un schéma cohérent dès le premier jour. Incluez systématiquement le trace_id pour permettre la corrélation. Utilisez les niveaux de log correctement : ERROR pour les erreurs, pas pour les avertissements. Échantillonnez les logs DEBUG en production — ils sont utiles pour le développement, coûteux à stocker à l’échelle.

Pour les métriques, respectez la cardinalité comme règle d’or. Utilisez les percentiles (p50, p90, p99) plutôt que la moyenne — la moyenne cache les valeurs extrêmes qui impactent les utilisateurs. Nommez de façon cohérente : http_request_duration_seconds plutôt que api_latency_ms. Alertez sur les symptômes (latence utilisateur élevée) plutôt que sur les causes (CPU élevé).

Pour les traces, propagez le contexte à travers tous les services, y compris les files de messages. Échantillonnez intelligemment : 100% des requêtes en erreur, un pourcentage du trafic normal. Ajoutez des attributs métier aux spans : user_tier, feature_flag, transaction_type. Instrumentez les appels externes — c’est souvent là que se cache la latence.

L’observabilité n’est pas une collection d’outils. C’est une propriété du système qui se conçoit dès l’architecture.

Le monitoring répond aux questions que vous avez anticipées. L’observabilité vous permet de répondre à des questions que vous n’aviez pas prévues.

Les trois piliers — logs, métriques, traces — apportent chacun une perspective différente. Les logs racontent le détail. Les métriques montrent les tendances. Les traces révèlent le parcours.

La corrélation via un identifiant commun (trace_id) est ce qui transforme trois outils séparés en un système de diagnostic intégré.

La cardinalité est le facteur de coût à surveiller. Les valeurs illimitées (user_id, request_id) vont dans les logs, pas dans les labels de métriques.

Un système observable vous permet de passer de “c’est lent” à “la cause racine est X” en minutes, pas en heures. C’est la différence entre dormir la nuit et passer des heures à reconstituer des puzzles à 3h du matin.