37 points par GN⁺ 2025-12-22 | 1 commentaires | Partager sur WhatsApp
  • 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.
  • 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_id a 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
    1. il ne décide pas quoi logger
    2. il n’ajoute pas automatiquement le contexte métier (par exemple : niveau d’abonnement, montant du panier, etc.)
    3. 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_code et 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
  • 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
    1. les erreurs (500, etc.) sont toujours conservées
    2. les requêtes lentes (p99 et au-delà) sont toujours conservées
    3. les utilisateurs VIP et les sessions marquées par certains flags sont toujours conservés
    4. 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 grep dans 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

 
GN⁺ 2025-12-22
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.

    • Comme il y a de l’authentification sur toute la stack, nous avons commencé à inclure le user id dans chaque ligne de log. Cela facilite beaucoup la vision d’ensemble de l’expérience vécue par un utilisateur
    • Enregistrer les erreurs sur une ligne distincte des logs de requête est pénible. On peut filtrer par trace, mais il est difficile de construire une requête du type « montre-moi uniquement les erreurs liées à des requêtes 5xx »
    • Ajouter ce type de contexte ne suffit pas : il faut aussi former les collègues au fait que de nouveaux champs existent. J’ai souvent vu des gens se compliquer la vie simplement parce qu’ils ne le savaient pas
    • Investir dans de meilleurs outils de tracing permet un niveau de débogage impossible à atteindre avec de simples logs. C’est en quelque sorte une extension de l’idée d’utiliser le user id dans les traces
    • S’il existe un concept de request ID dans la base de code, on peut aussi s’en servir pour suivre plus précisément le comportement d’un utilisateur
    • Si on impose TID dans l’ensemble des services, n’importe quelle équipe peut suivre toute la transaction à partir d’un seul TID
    • Ce genre de commentaire du style « ça sent l’IA » risque bientôt de devenir une culture critiquée
  • 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

    • En revanche, ce n’est pas elle qui a inventé le terme « observability ». Le concept existait déjà depuis des décennies dans plusieurs domaines. C’est une praticienne influente, mais pas la créatrice du terme
    • Son blog et l’histoire de la création de Honeycomb valent vraiment la lecture pour les gens du secteur. C’était l’une des premières équipes à reconnaître la valeur de cette approche
    • Le texte ressemblait tellement à son style que je m’attendais à voir une pub pour Honeycomb à la fin ; j’ai été surpris que ce ne soit pas le cas
    • Dans l’écosystème .NET, Nick Blumhardt travaille depuis longtemps sur le structured logging, et Seq comme Serilog le prennent en charge
    • Son contenu est de qualité, mais personne n’a « brandé » l’observability à lui seul. Il faut respecter son apport sans tomber dans l’exagération
  • 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

    • Si le problème est la visibilité de la couche intermédiaire, c’est simplement que l’événement n’est pas assez wide. log.error(data) ou wide_event.attach(error, data), au fond, c’est la même chose
    • Des logs du type « connection X:Y accepted at Z ns » et « closed at Z ns » sont extrêmement utiles pour déboguer les systèmes lents
    • Dans un framework PHP, j’ai résolu cela en créant une LoggerInterface. Les exceptions sont interceptées par un gestionnaire global et stockées en base sous forme wide. Il y a un peu de boilerplate, mais cela fonctionne tellement bien que je ne pourrais plus m’en passer
  • La 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.log suffit 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)

    • Avec des logs JSON, on peut toujours chercher avec grep '"uid": "user-123"'. L’option --context permet aussi de voir les lignes autour
  • J’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 servent à reconstituer une timeline, pas à contenir toutes les données d’une requête ou d’une réponse. Si on y met trop d’informations, cela devient au contraire plus difficile à comprendre.
      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
    • 400 Mo de logs par heure, ce n’est en réalité pas énorme. Dans ce cas, un simple grep suffit largement
  • 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

    • Chez Cloudflare, ils utilisent un échantillonnage adaptatif. Les lots de logs sont répartis en buckets selon leurs champs, puis on ne conserve dans chaque bucket que la racine carrée ou le logarithme du nombre de logs en entrée.
      Plus le volume de logs augmente, plus le taux d’échantillonnage s’ajuste automatiquement, ce qui évite de surcharger le système
    • Ce genre de seuil magique est risqué. Des valeurs comme P(99) devraient être mises à jour dynamiquement. Si le provider OTEL récupère régulièrement les valeurs réelles, c’est plus sûr
    • Un service en production doit être conçu pour que la collecte de logs s’adapte à la demande. Rien que le buffering sur disque local peut déjà beaucoup aider
    • Sur un service à fort trafic, on peut échantillonner les requêtes saines avec quelque chose comme trace_id mod 100 == 0
    • Si les logs deviennent un goulot d’étranglement, c’est que l’architecture du système est mauvaise. Un logging efficace peut traiter des centaines de millions d’événements par seconde
  • Dans 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é

    • En réalité, ce domaine et cet article servent à promouvoir le SaaS d’observability de l’auteur. Il faut un compte Cloudflare, mais comme c’est gratuit, cela ressemble à une stratégie marketing de long terme. Cela dit, j’ai trouvé ça utile, et comme j’ai déjà un compte CF, je pense l’essayer
    • Cet article s’inscrit dans la même veine que « Give people something to link to » de Simon Willison
    • Cela ressemble davantage à une landing page de génération de leads pour du marketing digital qu’à un billet de blog. La promotion du service est évidente
  • 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

    • Cela dit, les logs ne servent pas seulement à l’analyse de cause racine : ils peuvent aussi fournir des insights métier comme qui a été impacté, la corrélation entre performance et types d’entrée, ou encore l’impact de vulnérabilités de sécurité.
      Des logs riches en contexte, combinés à un moteur analytique, peuvent aussi contribuer à l’amélioration du produit
    • À l’affirmation « une requête traverse 15 services et 3 bases de données », certains ont répondu qu’il fallait éviter ce niveau de complexité
    • Pour ma part, je trouve que APN/Kibana suffit largement pour l’analyse de logs
  • 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

    • Je soutiens une « théorie unifiée de l’observability ». Logs, métriques et audit ne sont au fond que des flux de bits, transformables sans perte.
      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