Des journaux structurés avec identifiant de requête, sinon rien
L'affirmation Des lignes de journal en texte libre sans identifiant de corrélation ne sont pas des données de diagnostic. C'est un journal intime. Pendant un incident, vous ne pouv...
L'affirmation
Des lignes de journal en texte libre sans identifiant de corrélation ne sont pas des données de diagnostic. C'est un journal intime. Pendant un incident, vous ne pouvez pas répondre à la seule question qui compte — qu'est-il arrivé à cette requête — parce que les douze lignes qui la concernent sont entrelacées avec quatre mille lignes provenant de toutes les autres requêtes servies au même moment. Ajouter un identifiant de requête et passer au JSON prend un après-midi et change la nature même de vos journaux.
À quoi ressemble le journal intime
[2026-08-24 10:31:02] Traitement de la commande
[2026-08-24 10:31:02] Appel a la passerelle de paiement
[2026-08-24 10:31:03] Utilisateur introuvable
[2026-08-24 10:31:03] Traitement de la commande
Quelle commande ? Quel utilisateur ? L'« utilisateur introuvable » se rapporte-t-il à l'appel de paiement au-dessus, ou à une autre requête qui s'exécutait en parallèle ? Sur un serveur traitant 40 requêtes par seconde, la proximité dans le fichier ne signifie strictement rien.
À quoi cela devrait ressembler
{"ts":"2026-08-24T10:31:02.418Z","level":"info","req_id":"01J2K9X4","route":"POST /orders","user_id":8812,"order_id":4821,"msg":"commande creee","duration_ms":86}
{"ts":"2026-08-24T10:31:02.902Z","level":"error","req_id":"01J2K9X4","route":"POST /orders","order_id":4821,"msg":"expiration passerelle","provider":"moneris","attempt":2,"duration_ms":30011}
Un seul filtre reconstitue désormais toute la vie d'une requête :
jq -c 'select(.req_id=="01J2K9X4")' app.log
Et une seule agrégation répond à une question qu'il fallait auparavant deviner :
jq -r 'select(.level=="error") | .provider' app.log | sort | uniq -c | sort -rn
Générer et propager l'identifiant
Acceptez un en-tête X-Request-Id entrant si le répartiteur en fournit un ; sinon, générez un ULID ou un UUID à l'extrême bordure de la requête. Rangez-le dans un contexte ou une variable locale au fil d'exécution pour que chaque appel de journalisation le récupère sans qu'on ait à le transmettre explicitement. Dans Nginx :
proxy_set_header X-Request-Id $request_id;
log_format json escape=json '{"ts":"$time_iso8601","req_id":"$request_id",'
'"status":$status,"rt":$request_time,"uri":"$request_uri"}';
L'étape déterminante est la propagation. Transmettez le même identifiant à vos tâches d'arrière-plan, à vos appels d'API sortants et à votre outil de suivi d'erreurs. Quand une cliente écrit au sujet d'une commande ratée, vous voulez coller un identifiant et voir la requête Web, la tâche mise en file et l'appel tiers qui a échoué — en une seule interrogation, à travers trois systèmes.
Affichez-le aussi à la clientèle. Mettre l'identifiant sur votre page d'erreur transforme « le site a planté ce matin » en recherche exacte.
Les champs à normaliser
Entendez-vous une fois sur les noms et faites-les respecter en revue : user_id, userId et uid dans trois services, et vos agrégations manquent silencieusement les deux tiers des données.
tsen ISO 8601 avec les millisecondes et un décalage UTC explicite. Jamais l'heure locale : les changements d'heure de mars et de novembre produisent une heure d'horodatages dupliqués ou manquants qui ne vous embrouillera qu'une seule fois, mais durablement.level,msg,req_id,route,duration_ms,status.- Les identifiants métier comme champs distincts, non interpolés dans le message.
"order_id": 4821s'interroge ;"echec du traitement de la commande 4821"ne s'interroge pas.
Ce qui ne doit jamais y figurer
Les journaux sont expédiés vers des services tiers, répliqués dans les sauvegardes et lus par des sous-traitants. Écartez-en les numéros de carte complets, les mots de passe, les jetons de session, les en-têtes d'autorisation et tout dossier personnel complet. L'accident courant consiste à journaliser le corps entier d'une requête en cas d'erreur, ce qui capture un mot de passe sur la route de connexion.
Journalisez des identifiants et les quatre derniers chiffres, pas des valeurs. S'il vous faut consigner une adresse courriel à des fins de soutien, décidez-le délibérément et inscrivez-le dans votre politique de conservation plutôt que de le découvrir lors d'une vérification de confidentialité.
Conservation et volume
Les journaux structurés sont plus volumineux que le texte : environ deux à trois fois par ligne. Pour un site servant un million de requêtes par mois à quatre lignes chacune, comptez de 8 à 15 Go. C'est négligeable sur disque et coûteux sur un forfait facturé au gigaoctet ingéré ; décidez donc du partage sciemment : 30 jours interrogeables dans un outil hébergé, 12 mois compressés en stockage objet pour quelques dollars par mois.
gzip -9 app-2026-07.log # souvent 12:1 sur des journaux JSON
Le test
Choisissez une vraie requête d'hier. Chronométrez-vous en reconstituant tout ce qui lui est arrivé. Moins de trente secondes : votre journalisation fonctionne. S'il faut dix minutes de grep et de déduction, vous ne le ferez pas à 2 h du matin quand ce sera important, et vos journaux servent de réconfort plutôt que d'instrumentation.