Observabilité : vision à rayons X pour les systèmes distribués
Pourquoi les journaux ne suffisent pas. Un guide technique approfondi sur la philosophie OpenTelemetry, Structured Logging et SRE Alerting (SLI/SLO).
“Le site est lent.”
Ce ticket de quatre mots est le fléau de chaque équipe d’ingénierie. Lent où ? La base de données est-elle verrouillée par le processeur ? Le réseau mobile est-il fragile ? L’API d’expédition tierce expire-t-elle ? Avons-nous déployé du mauvais code hier ?
Si votre stratégie de débogage repose sur « console.log » et sur la vérification des graphiques du processeur du serveur, vous déboguez dans le noir. Surveillance vous indique que le système est en panne (tableau de bord rouge). Observabilité vous indique pourquoi il s’est cassé.
Chez Maison Code Paris, nous exploitons des plateformes commerciales à fort trafic où 1 minute d’indisponibilité équivaut à des dizaines de milliers d’euros. Nous ne devinons pas. Nous utilisons l’instrumentation de code pour obtenir une vision aux rayons X dans la pile distribuée.
Pourquoi Maison Code en parle
Chez Maison Code Paris, nous agissons comme la conscience architecturale de nos clients. Nous héritons souvent de stacks “modernes” construites sans compréhension fondamentale de l’échelle.
Nous abordons ce sujet car il représente un point de pivot critique dans la maturité de l’ingénierie. Une mise en œuvre correcte différencie un MVP fragile d’une plateforme résiliente de niveau entreprise.
Les trois piliers de l’observabilité
Pour comprendre un système complexe, vous avez besoin de trois types distincts de données télémétriques :
- Journaux : événements discrets. “Il s’est passé quelque chose à 10h00’01”.
- Mesures : chiffres agrégés. “Le processeur était à 80 % pendant 5 minutes.”
- Traces : le cycle de vie d’une requête. “L’utilisateur a cliqué sur le bouton -> API -> DB -> API -> UI.”
1. Journaux : structurés et consultables
Les développeurs adorent « console.log(“Error user not found ” + id)`. Les DevOps détestent ça. Dans un système produisant 1 000 journaux par seconde, la recherche de « Utilisateur d’erreur » est lente. L’analyser est impossible. Vous ne pouvez pas représenter graphiquement le « taux d’erreur par ID utilisateur ».
La règle d’or : les journaux doivent être JSON structuré.
{
"level": "erreur",
"message": "Délai d'expiration de la passerelle de paiement",
"horodatage": "2025-10-23T14:00:00Z",
"service": "checkout-api",
"contexte": {
"IDutilisateur": "u_123",
"cartId": "c_456",
"gateway": "bande",
"latence": 5002
},
"traceId": "a1b2c3d4e5f6"
}
Désormais, dans des outils comme Datadog ou ELK (Elasticsearch), vous pouvez exécuter des requêtes :
service:checkout-api @context.gateway:stripe @level:error- “Montrez-moi un graphique des erreurs de paiement regroupées par Gateway.”
2. Métriques : le pouls
Les métriques sont peu coûteuses à stocker. Ce ne sont que des chiffres.
- Compteurs : “Total des demandes” (monte).
- Jauges : “Utilisation de la mémoire” (monte et descend).
- Histogrammes : “Latency Distribution” (95% des requêtes < 200ms).
Le piège de la cardinalité :
Les ingénieurs juniors essaient souvent d’étiqueter les métriques avec des données à cardinalité élevée.
http_request_duration_seconds{user_id="u_123"}.
Si vous avez 1 million d’utilisateurs, vous créez 1 million de séries chronologiques. Cela fera planter votre serveur Prometheus ou mettra votre compte Datadog en faillite.
Règle : Les métriques concernent l’état de santé du système. Les journaux/traces sont destinés aux Spécificités de l’utilisateur.
3. Traçage : le contexte
Dans une architecture Microservices ou Headless, un seul clic d’utilisateur atteint : CDN -> Fonction Edge -> API de nœud -> Base de données -> API tierce. Si la requête prend 3 secondes, une métrique indique « Latence élevée ». Une Trace vous montre :
- API de nœud : 10 ms
- Base de données : 5 ms
- API d’expédition : 2 900 ms
Le traçage résout le « jeu du blâme ».
OpenTelemetry : le standard de l’industrie
Historiquement, il fallait installer le SDK Datadog, ou le SDK New Relic. Si vous vouliez changer de fournisseur, vous deviez réécrire le code. OpenTelemetry (OTel) est le standard ouvert (CNCF) pour la collecte de télémétrie. Vous instrumentez votre code une fois avec OTel. Vous pouvez ensuite rediriger ces données vers Datadog, Prometheus, Jaeger ou simplement « stdout ».
Auto-instrumentation Node.js
L’OTel moderne permet “l’auto-instrumentation”. Vous ne réécrivez pas vos gestionnaires Express. Il corrige les bibliothèques standard (http, pg, redis) au moment de l’exécution.
// instrumentation.ts
importer { NodeSDK } depuis '@opentelemetry/sdk-node' ;
importer { HttpInstrumentation } depuis '@opentelemetry/instrumentation-http' ;
importer { PgInstrumentation } depuis '@opentelemetry/instrumentation-pg' ;
importer { OTLPTraceExporter } depuis '@opentelemetry/exporter-trace-otlp-proto' ;
const sdk = nouveau NodeSDK ({
traceExporter : nouveau OTLPTraceExporter({
url : 'https://api.honeycomb.io/v1/traces', // Ou votre collectionneur
}),
instruments : [
new HttpInstrumentation(), // Trace tous les HTTP entrants/sortants
new PgInstrumentation(), // Trace toutes les requêtes Postgres
],
serviceName : 'maison-code-api',
});
sdk.start();
Avec ce fichier de 20 lignes, vous disposez instantanément de graphiques Waterfall pour chaque requête de base de données et appel d’API dans votre système de production.
Propagation du contexte de trace
Comment la base de données sait-elle quel « clic utilisateur » a provoqué la requête ?
Propagation de contexte.
Lorsque le service A appelle le service B, il injecte un en-tête HTTP générique : traceparent.
traceur : 00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01
Le service B lit cet en-tête. Il démarre sa propre étendue, en utilisant l’ID de A comme “ID parent”. Cela relie les opérations distribuées en un seul DAG (Directed Acyclic Graph).
RUM (surveillance des utilisateurs réels)
L’observabilité côté serveur fonctionne parfaitement, mais les utilisateurs se plaignent toujours. “J’ai cliqué sur le bouton et rien ne s’est passé.” Journaux du serveur : “Aucune demande reçue.” Conclusion : Le JavaScript s’est écrasé dans le navigateur avant l’envoi de la requête.
Pour l’observabilité frontend, nous utilisons RUM (Sentry, LogRocket). Il capture automatiquement :
- Core Web Vitals : plus grande peinture de contenu (LCP), interaction avec la peinture suivante (INP).
- Erreurs de console : « undéfini n’est pas une fonction ».
- Session Replay : un enregistrement de type vidéo des mouvements de la souris de l’utilisateur.
Étude de cas : Nous avons rencontré un bug de paiement avec 0 journal. En regardant Session Replay, nous avons vu que les utilisateurs d’iPhone SE (petit écran) ne pouvaient pas faire défiler jusqu’au bouton « Payer » car une « bannière de cookies » le recouvrait avec « .zIndex : 9999 ». Aucun journal n’aurait pu nous le dire. L’observabilité visuelle l’a fait.
Philosophie d’alerte : principes SRE
N’appelez pas l’ingénieur à 3 heures du matin car « le processeur est à 90 % ». Peut-être que 90%, c’est bien. Peut-être que la file d’attente est traitée rapidement. Alerte sur les symptômes, pas sur les causes.
SLI (Service Level Indicator) : une métrique importante pour l’utilisateur.
- Exemple : “Disponibilité de la page d’accueil”.
- Exemple : « Latence de paiement ».
SLO (Service Level Objective) : l’objectif.
- “La page d’accueil devrait être 200 OK 99,9 % du temps.”
- “Le paiement doit être inférieur à 2 s dans 95 % des cas.”
Condition d’alerte :
- “Si taux d’erreur > 0,1 % pendant 5 minutes -> PagerDuty.”
- “Si taux d’erreur > 5% -> Réveillez le PDG.”
Le coût de l’observabilité
Tout observer coûte cher. Si vous tracez 100% des requêtes, votre facture de surveillance pourrait dépasser votre facture d’hébergement. L’échantillonnage est la solution.
- Échantillonnage basé sur la tête : décidez au début d’une requête. “Tracez 10 % des utilisateurs.”
- Échantillonnage basé sur la queue (avancé) : conservez toutes les traces en mémoire. Si une erreur se produit, envoyez la trace complète. Si cela réussit, jetez-le.
- Cela garantit que vous capturez 100 % des erreurs mais 0 % des journaux de réussite ennuyeux.
10. Surveillance de la logique métier (les signaux d’or)
Les graphiques CPU ne paient pas les factures. Les commandes paient les factures. Les journaux d’accès ne vous indiquent pas si le bouton « Ajouter au panier » est cassé (s’il est cassé, il n’y a pas de journaux). Nous définissons les Business Metrics :
commandes_par_minuteadd_to_cart_value_totalpayment_gateway_rejection_rateNous définissons des alertes « Détection d’anomalies ». “Si les commandes/min diminuent de 50 % par rapport à mardi dernier -> PagerDuty.” Cela détecte les « échecs silencieux » (par exemple, un écouteur d’événement Javascript cassé) que les journaux du serveur ne verront jamais.
11. Stratégies de contrôle des coûts
Datadog coûte cher. Stocker chaque « console.log » est un gaspillage. Nous implémentons des Niveaux de journalisation par environnement :
Développement: Débogage (Tout).Production: Info (Événements clés) + Erreur. Nous utilisons également des Filtres d’exclusion au niveau de l’agent : “Supprimez tous les journaux contenantHealth Check OK”. Cela réduit le volume de 40 % sans perte de signal.
12. L’explosion de la cardinalité (Comment mettre en faillite l’observabilité)
Cela commence innocent.
metrics.increment('request_duration', { url : req.url })
Ensuite, un bot clique sur /login?random=123.
Puis /login?random=456.
Soudain, vous disposez d’un million de valeurs de balises uniques.
Datadog vous facture les « métriques personnalisées ».
Facture : 15 000€/mois.
Correction : normalisez vos dimensions.
Remplacez /login?random=123 par /login?random=* dans votre middleware avant d’émettre la métrique.
13. ROI de la journalisation : ce journal vaut-il 0,001 € ?
Nous traitons les bûches comme un bien immobilier. “Utilisateur connecté” -> Valeur élevée. Se conserve 30 jours. “Bilan de santé réussi” -> Valeur faible. Lâchez immédiatement. “Dump du tableau de débogage” -> Valeur négative. Cela encombre la recherche. Nous implémentons l’Échantillonnage dynamique : Lors d’un incident, activez DEBUG pour 1 % des utilisateurs. En temps de paix, gardez-le éteint.
14. Conclusion
L’observabilité est la différence entre « Je pense que ça marche » et « Je sais que ça marche ». Cela fait passer la culture du « Blâme » (« L’équipe réseau a échoué ») à « Données » (« La trace affiche un délai d’attente de 500 ms sur le commutateur »).
Dans un environnement moderne, distribué et aux enjeux élevés, le code sans instrumentation n’est pratiquement pas du code. C’est une boîte noire qui attend de vous embrouiller.
Pouvez-vous voir à l’intérieur de votre pile ?
Si vous déboguez avec « console.log », vous perdez de l’argent. Engagez nos Architectes.