Le logging est un désastre
(loggingsucks.com)- Dans les systèmes distribués modernes, les approches de logging traditionnelles ont une limite structurelle : elles ne parviennent pas à restituer la vérité
- Les logs restent conçus selon l’hypothèse d’un environnement à serveur unique façon 2005, et perdent donc le contexte d’une requête qui traverse plusieurs services, bases de données et caches
- Une simple recherche de chaînes ne comprend ni la structure, ni les relations, ni les corrélations, ce qui rend la recherche de la cause d’un problème difficile
- La solution consiste à enregistrer pour chaque requête un unique “Wide Event” (ou “Canonical Log Line”) contenant tout le contexte
- Cela transforme les logs, qui ne sont plus un simple texte mais un actif de données exploitable pour l’analyse
Le problème fondamental du logging
- Les logs traditionnels ont été conçus à l’époque des serveurs monolithiques et ne reflètent pas l’architecture moderne des services distribués
- Une requête traverse plusieurs services, bases de données, caches et files de messages, mais les logs continuent d’être écrits comme s’ils provenaient d’un seul serveur
- Dans l’exemple de logs, une seule requête génère 13 lignes ; avec 10 000 utilisateurs simultanés, cela représente 130 000 lignes par seconde, dont la plupart n’apportent rien
- En cas d’incident, ce qu’il faut, c’est du contexte, or les logs actuels en manquent
Les limites de la recherche textuelle
- Lorsqu’un utilisateur signale que « le paiement ne fonctionne pas », chercher dans les logs par e-mail ou par user_id donne rarement des résultats utiles, faute de structure cohérente
- Le même identifiant utilisateur peut être enregistré sous des dizaines de formes :
user-123,user_id=user-123,{"userId":"user-123"}, etc.
- Le même identifiant utilisateur peut être enregistré sous des dizaines de formes :
- Les formats de logs diffèrent d’un service à l’autre, ce qui rend impossible le suivi des événements liés
- Le problème central est que les logs sont conçus pour l’écriture (write), et non optimisés pour la requête (query)
Définitions des concepts clés
- Structured Logging : méthode qui consiste à enregistrer les événements sous forme de paires clé-valeur (JSON) plutôt que comme de simples chaînes
- Cardinality : nombre de valeurs distinctes d’un champ ; par exemple,
user_ida une cardinalité très élevée - Dimensionality : nombre de champs dans un événement de log ; plus il y en a, plus le potentiel d’analyse est élevé
- Wide Event / Canonical Log Line : un seul événement de log riche en contexte par requête
- La plupart des systèmes de logging limitent les données à forte cardinalité pour des raisons de coût, alors qu’en pratique ce sont souvent les plus utiles pour le débogage
Les limites d’OpenTelemetry
- OpenTelemetry (OTel) est un ensemble de protocoles et de SDK qui ne fournit qu’un standard de collecte et de transport des données
- En revanche, OTel ne fait pas les choses suivantes
- il ne décide pas quoi logger
- il n’ajoute pas automatiquement le contexte métier (par exemple : niveau d’abonnement, montant du panier, etc.)
- il ne change pas la façon de penser le logging des développeurs
- Même avec la même bibliothèque, l’expérience de débogage est radicalement différente entre une instrumentation qui ajoute volontairement du contexte et une instrumentation minimale
- OTel n’est qu’une simple tuyauterie (plumbing) ; c’est au développeur de décider ce qu’il y fait circuler
L’approche Wide Event / Canonical Log Line
- Il faut abandonner un logging centré sur « ce que fait le code » pour enregistrer plutôt « ce qui est arrivé à la requête »
- Pour chaque requête, on génère un événement large au niveau du service
- Il peut inclure plus de 50 champs liés à la requête, à l’utilisateur, au paiement, aux erreurs, à l’environnement, etc.
- Dans l’exemple JSON,
user_id,subscription_tier,service_version,error_codeet tous les autres éléments de contexte utiles au débogage sont présents - Cela permet, en une seule recherche, d’analyser immédiatement des questions comme « pourquoi les paiements échouent-ils chez les utilisateurs premium ? »
Utilisation des requêtes sur les Wide Events
- Les Wide Events ne se traitent pas comme une simple recherche textuelle, mais via des requêtes sur des données structurées
- Grâce à des données de forte cardinalité et de grande dimension, on peut faire du débogage au niveau d’une analyse en temps réel
- Exemple : exécuter immédiatement une requête du type « agréger le taux d’échec des paiements des utilisateurs premium au cours de la dernière heure, par code d’erreur »
Schéma d’implémentation
- On construit l’événement tout au long du cycle de vie de la requête, puis on ne l’émet qu’une seule fois à la fin
- Dans le middleware, on initialise les champs de base comme
request_id,timestamp,method,path, etc. - Dans le handler, on ajoute progressivement les informations sur l’utilisateur, le panier, le paiement et les erreurs
- Dans le middleware, on initialise les champs de base comme
- Au final, on enregistre un unique événement JSON avec
logger.info(event)
Contrôler les coûts par l’échantillonnage
- Enregistrer plus de 50 champs par requête fait rapidement grimper les coûts ; il faut donc échantillonner
- Un échantillonnage purement aléatoire risque de laisser passer des erreurs
- Une stratégie de Tail Sampling est proposée
- les erreurs (500, etc.) sont toujours conservées
- les requêtes lentes (p99 et au-delà) sont toujours conservées
- les utilisateurs VIP et les sessions marquées par certains flags sont toujours conservés
- pour le reste, seuls 1 à 5 % sont échantillonnés aléatoirement
- Cela permet à la fois de réduire les coûts et de préserver les événements clés
Clarification de quelques idées reçues
- Structured Logging ≠ Wide Event : un format JSON ne suffit pas ; le contexte est l’élément essentiel
- Utiliser OpenTelemetry ≠ obtenir une observabilité complète : la collecte est standardisée, mais le contenu des logs reste de la responsabilité du développeur
- Ce n’est pas la même chose que le tracing : le tracing montre le flux entre services, tandis que le Wide Event fournit le contexte interne au service
- La séparation « les logs servent au débogage, les métriques aux dashboards » n’est pas nécessaire — les Wide Events couvrent les deux usages
- L’idée selon laquelle les données à forte cardinalité coûtent cher est dépassée ; des bases modernes comme ClickHouse et BigQuery les traitent efficacement
Les effets de l’adoption des Wide Events
- Le débogage passe de l’archéologie à l’analyse
- Au lieu de faire des
grepdans les logs de 50 services pour retrouver un « échec de paiement utilisateur »,
on passe à une analyse fondée sur une requête unique, du type « consulter le taux d’échec des paiements des utilisateurs premium par code d’erreur » - Au final, les logs cessent d’être un outil qui ment, pour devenir un actif de données qui dit la vérité
1 commentaires
Avis sur Hacker News
Le texte était difficile à lire et donnait l’impression d’avoir été aidé par une IA. Cela dit, le message avait de la valeur, et il aurait sans doute gagné à être plus concis.
Voici quelques réflexions récentes à ce sujet.
Impossible de parler de ce sujet sans mentionner Charity Majors. Elle diffuse depuis plus de dix ans les concepts de « wide events » et d’« observability », et a bâti Honeycomb.io sur cette philosophie.
Aujourd’hui, on peut mettre cette approche en œuvre avec divers outils. L’important est de capturer des wide events via des structured logs ou des traces, puis d’utiliser des outils riches en visualisations comme les séries temporelles ou les histogrammes
Je suis partiellement d’accord avec l’article, mais l’approche consistant à ne garder qu’un seul wide event a ses pièges. Si une exception ou un timeout survient au milieu de la requête, il ne reste plus rien.
On passe aussi à côté du framework de logging natif du langage et des logs des dépendances.
C’est pourquoi il vaut mieux utiliser cela comme une couche supplémentaire par-dessus les logs existants. Il suffit d’avoir un ID au niveau request/session et d’agréger ensuite dans quelque chose comme ClickHouse
log.error(data)ouwide_event.attach(error, data), au fond, c’est la même choseLa présentation et les exemples interactifs étaient excellents. Mais au final, cela se résume à « ajoutez des tags structurés dans les logs ».
J’ai l’impression que les wide logs n’apportent pas un gain suffisant au regard de la complexité et de la perte de lisibilité.
Un simple
grep "uid=user-123" application.logsuffit souvent ; je ne vois pas toujours l’intérêt d’y ajouter jusqu’au mode de livraison de l’utilisateur.(À noter : dans le navigateur Brave sur Android, les cases à cocher ne fonctionnaient pas)
grep '"uid": "user-123"'. L’option--contextpermet aussi de voir les lignes autourJ’ai travaillé dans un environnement de fabrication de semi-conducteurs avec un système comptant des milliers de participants sur le bus de messages. On produisait 300 à 400 Mo de logs par heure, mais c’était parfaitement gérable avec grep et des outils CLI.
Les logs n’étaient qu’une série temporelle d’événements, et l’analyse détaillée se faisait via des requêtes Oracle. Les logs servent à comprendre la causalité entre les événements
Les logs disent « quand » et « quoi » s’est produit ; le « pourquoi » se trouve dans la combinaison du code, des données et des événements
Personnellement, je trouve des interfaces comme la stack ELK peu pratiques pour l’exploration intuitive. Pour moi, il est important de pouvoir lire les logs en les suivant instinctivement
Le conseil donné à la fin de l’article — « loggez toutes les erreurs, exceptions et requêtes lentes » — est une idée dangereuse.
Par exemple, si une dépendance devient lente, le volume de logs peut exploser par un facteur 100.
En situation d’incident, un service doit faire moins de travail pour pouvoir se rétablir ; une explosion des logs peut au contraire provoquer une défaillance en cascade
Plus le volume de logs augmente, plus le taux d’échantillonnage s’ajuste automatiquement, ce qui évite de surcharger le système
trace_id mod 100 == 0Dans les logiciels modernes, il est difficile d’expliquer complètement « ce qui s’est passé » avec un seul log.
C’est pourquoi il faut une corrélation verticale (Vertical correlation) et une corrélation horizontale (Horizontal correlation).
Entre les couches d’une même stack, il faut partager la même valeur de corrélation, et lors des communications inter-systèmes, il faut une corrélation entre pairs.
Ajouter ces valeurs à des API ou des protocoles est difficile, mais si l’on prévoit dès le départ un ID de transaction, on peut retracer l’ensemble du parcours
Je trouve qu’enregistrer un domaine dédié pour un seul article manque de pérennité.
Comme il faut payer le renouvellement chaque année, il vaudrait mieux utiliser un blog personnel ou un sous-domaine.
Par exemple, quelque chose comme logging-sucks.boristane.com serait plus approprié
Concernant l’idée que « les logs sont un vestige de l’époque monolithique », je pense au contraire que les logs locaux restent pertinents.
Leur rôle d’origine est d’enregistrer la conversation d’un processus local, et pour comprendre ce qui se passe sur d’autres serveurs, il faut du transaction tracing.
Avec des logs placés au bon endroit, on peut toujours remonter à la cause racine
Des logs riches en contexte, combinés à un moteur analytique, peuvent aussi contribuer à l’amélioration du produit
Je suis d’accord avec l’idée de « logguer non pas ce que fait le code, mais ce qui arrive à la requête », mais l’auteur m’a semblé manquer d’expérience.
J’appelle cela le « bug parts logging », et je pense qu’il faut y inclure des signaux précurseurs comme le chemin de traitement, le nombre de passages ou la durée.
Le logging n’est pas la même chose que les métriques ou l’audit. Si le logging échoue, le traitement doit continuer ; en revanche, l’échec d’un audit est critique.
Comme avec le concept de « historian » dans les systèmes SCADA, il faut distinguer les observables et les évaluatifs.
Par exemple, les événements détaillés d’un capteur de carburant sont utiles pour le diagnostic, mais inutiles pour répondre à la question « peut-on atteindre la destination ? ».
Au fond, l’essentiel est de définir clairement ce qu’il faut observer et ce qu’il faut évaluer
Les modes de stockage, de transformation et de requête diffèrent, mais on peut concevoir de façon identique les points de consommation et les mécanismes.
Cela simplifie l’architecture du système et permet aussi de retraiter plus tard des logs conservés à long terme