Aller au contenu
medium

Les logs : comprendre le signal le plus riche (et le plus cher)

20 min de lecture

Votre application plante en production à 3 h du matin. L’alerte dit “erreur 500”, mais pas pourquoi. Vous ouvrez les logs, et vous tombez sur des milliers de lignes en texte libre, sans structure, mélangées entre 12 services. Trouver la cause revient à chercher une aiguille dans une botte de foin — avec un grep. Les logs sont le signal d’observabilité le plus riche (chaque événement peut contenir un contexte complet) mais aussi le plus coûteux en stockage et le plus difficile à exploiter s’ils ne sont pas structurés.

  • Qu’est-ce qu’un log : événement discret vs métrique agrégée
  • Structuré vs non structuré : pourquoi le JSON change tout
  • Niveaux de sévérité : DEBUG, INFO, WARN, ERROR, FATAL — quand utiliser chacun
  • Les champs essentiels : les 6 champs qu’un log structuré doit contenir
  • Ce qu’il ne faut pas logger : PII, secrets, données sensibles
  • Volume et coûts : pourquoi les logs sont le signal le plus cher
  • Le pipeline de logs : de l’émission au requêtage

Un log (ou journal) est un événement discret et horodaté : il décrit quelque chose qui s’est passé à un instant précis. Chaque requête HTTP traitée, chaque erreur rencontrée, chaque connexion à la base de données peut générer une ligne de log.

Contrairement à une métrique qui agrège des valeurs dans le temps (ex. : “142 requêtes/seconde”), un log conserve le détail individuel de chaque événement. Cela le rend extrêmement riche pour le diagnostic, mais aussi beaucoup plus volumineux à stocker.

Un log fonctionne comme le carnet de bord d’un navire : chaque événement est noté avec l’heure, les circonstances et les détails pertinents. Le capitaine n’écrit pas “en moyenne, la mer était calme aujourd’hui” (c’est une métrique) — il note “14 h 32 : vent force 7, changement de cap vers le sud-est” (c’est un log).

CaractéristiqueLogMétrique
NatureÉvénement discretValeur numérique agrégée
GranularitéChaque occurrence individuelleAgrégation sur une fenêtre de temps
VolumeÉlevé (1 ligne par événement)Faible (1 point par intervalle)
Coût de stockageÉlevéFaible
RequêtageRecherche textuelle / filtrage par champsCalculs mathématiques (rate, sum, avg)
Usage principalDiagnostic, audit, debugAlerting, tendances, dashboards

La différence entre un log utile et un log inutilisable tient souvent à un seul choix : structuré ou non.

C’est une ligne de texte libre, lisible par un humain mais difficile à exploiter par une machine :

2026-02-07 14:32:15 ERROR PaymentService - Payment failed for user 12345: insufficient funds (amount=99.99, balance=42.50)

Pour extraire l’identifiant utilisateur, le montant ou le type d’erreur, il faut écrire une expression régulière — fragile, différente pour chaque format, et qui casse dès que le message change.

Le même événement en JSON :

{
"timestamp": "2026-02-07T14:32:15.042Z",
"level": "ERROR",
"service": "payment-api",
"message": "Payment failed: insufficient funds",
"user_id": "12345",
"amount": 99.99,
"balance": 42.50,
"trace_id": "abc123def456",
"span_id": "789ghi"
}

Chaque champ est un clé/valeur typé. Un outil de requêtage peut filtrer instantanément par level="ERROR", service="payment-api" ou user_id="12345" — sans regex, sans ambiguïté.

CritèreNon structuréStructuré (JSON)
Lisibilité humaine bruteBonneCorrecte (avec jq)
Filtrage par champRegex fragileNatif (clé/valeur)
Corrélation avec les tracesManuelleAutomatique via trace_id
IndexationPlein texte uniquementPar champ — rapide et ciblé
Évolution du formatCasse les parseursAjout de champs sans rupture

Les niveaux de log (ou severity levels) indiquent l’importance d’un événement. La RFC 5424 (Syslog) en définit 8, mais la plupart des applications utilisent une échelle simplifiée à 5 niveaux.

NiveauQuand l’utiliserExemple
DEBUGDétails fins utiles uniquement en développement ou diagnostic ponctuel”Requête SQL exécutée : SELECT * FROM users WHERE id=12345 — durée 3 ms”
INFOÉvénements normaux qui marquent le bon fonctionnement”Serveur démarré sur le port 8080”, “Paiement de 99,99 € traité avec succès”
WARNSituation anormale mais non bloquante — le service continue”Pool de connexions à 85 % de capacité”, “Retry n°2 vers le service externe”
ERRORÉchec d’une opération — une requête ou une action a échoué”Paiement refusé : fonds insuffisants”, “Timeout de connexion à la base”
FATALErreur irrécupérable — le processus va s’arrêter”Impossible de lire le fichier de configuration”, “Port 8080 déjà occupé”

Le choix du niveau est un acte d’engagement envers l’équipe d’astreinte. Un WARN mal calibré génère du bruit ; un ERROR manquant masque un problème réel.

Deux questions pour choisir :

  1. Quelqu’un doit-il agir immédiatement ? → ERROR ou FATAL
  2. Est-ce que ça fonctionne encore ? → Si oui, WARN. Si non, ERROR.

Pour les systèmes qui utilisent syslog, voici la correspondance avec les 8 niveaux de la RFC 5424 :

CodeNiveau RFC 5424Correspondance application
0EmergencyFATAL (système inutilisable)
1AlertFATAL (action immédiate requise)
2CriticalFATAL / ERROR critique
3ErrorERROR
4WarningWARN
5NoticeINFO (événement significatif)
6InformationalINFO
7DebugDEBUG

Un log structuré utile contient au minimum 6 champs qui répondent aux questions fondamentales du diagnostic : quand, quoi, où, qui, et comment le relier aux autres signaux.

ChampPourquoi il est indispensableExemple
timestampQuand — ordonne les événements chronologiquement"2026-02-07T14:32:15.042Z" (ISO 8601, UTC)
levelGravité — permet le filtrage par sévérité"ERROR"
service — identifie le composant émetteur"payment-api"
messageQuoi — décrit l’événement en langage humain"Payment failed: insufficient funds"
trace_idCorrélation inter-services — relie le log à une trace distribuée (tracing)"abc123def456"
request_idCorrélation locale — regroupe les logs d’une même requête, utile même sans tracing"req-789ghi"

trace_id est propagé entre les services par le système de tracing distribué (OpenTelemetry, Jaeger…). request_id est généré à l’entrée (reverse-proxy ou API gateway) et transmis via un header (X-Request-ID) : il permet de corréler les logs d’une requête même si le tracing distribué n’est pas encore en place.

Le champ message doit rester lisible par un humain et stable dans le temps. Les détails variables (montant, identifiant, durée) vont dans des champs dédiés (error_type, duration_ms, amount…), pas dans le message lui-même.

  • "Payment failed: insufficient funds" + champ amount: 99.99
  • "Payment of 99.99 EUR failed for user 12345 after 127ms: insufficient funds"

Un message stable permet de grouper les logs par type d’événement. Si chaque message est unique (parce qu’il contient des valeurs), le groupement devient impossible.

ChampUsage
span_idSitue le log dans un span précis de la trace
environmentDistingue production / staging / dev
versionIdentifie la version de l’application déployée
hostname / pod_nameLocalise l’instance émettrice
user_idIdentifie l’utilisateur concerné (attention PII)
duration_msMesure la durée de l’opération loguée
error_typeCatégorise l’erreur (TimeoutError, ValidationError)
{
"timestamp": "2026-02-07T14:32:15.042Z",
"level": "ERROR",
"service": "payment-api",
"version": "2.3.1",
"environment": "production",
"hostname": "payment-api-7b4d9-xk2p",
"message": "Payment failed: insufficient funds",
"trace_id": "abc123def456",
"span_id": "789ghi",
"request_id": "req-a1b2c3",
"user_id": "usr_12345",
"amount": 99.99,
"currency": "EUR",
"error_type": "InsufficientFundsError",
"duration_ms": 127
}

Ce log permet en un coup d’oeil de répondre à : quand (timestamp), quoi (message + error_type), où (service + hostname), pour qui (user_id), et de naviguer vers la trace complète (trace_id).

Les logs traversent souvent des pipelines de collecte, des stockages partagés et des dashboards accessibles à plusieurs équipes. Certaines données ne doivent jamais s’y trouver.

CatégorieExemplesRisque
SecretsMots de passe, tokens API, clés privéesCompromission du système
Headers d’authentificationAuthorization, Cookie, Set-CookieTokens/sessions exposés en clair
PII (données personnelles)E-mail, adresse postale, numéro de téléphone, IPNon-conformité RGPD/CNIL
Données financièresNuméro de carte bancaire, IBAN completViolation PCI-DSS
Données médicalesDiagnostics, prescriptionsViolation réglementaire
  • Masquer les données sensibles avant l’émission (ex. : "card": "****1234")
  • Ne pas logger les corps de requêtes HTTP complets en production (ils contiennent souvent des formulaires avec des données utilisateur)
  • Identifier les champs PII et les exclure du pipeline de collecte ou les anonymiser dans le collecteur (ex. : processeur OTel transform)
  • En cas de doute, ne pas logger le champ — on peut toujours l’ajouter plus tard

Les logs sont, de loin, le signal d’observabilité le plus volumineux et le plus coûteux. En ordre de grandeur, une application web génère entre 1 et 10 Go de logs par jour (davantage sous fort trafic ou avec des logs verbeux). En comparaison, ses métriques Prometheus occupent quelques centaines de Mo, et ses traces (échantillonnées) quelques Go par semaine. Ces chiffres varient fortement selon le trafic, le nombre de services et le niveau de verbosité.

Le coût des logs est le produit de trois facteurs :

Volume × Rétention × Requêtage = Coût

FacteurCe qui l’augmenteLevier d’optimisation
VolumeLogs DEBUG en production, corps de requêtes, logs verbeuxRéduire le niveau en prod (INFO minimum), filtrer à la source
RétentionConservation illimitée (“on ne sait jamais”)Définir des politiques par importance : 7 j DEBUG, 30 j INFO/WARN, 90 j ERROR
RequêtageIndex plein texte sur tous les champsIndexer uniquement les champs utiles (labels dans Loki)
SignalVolume typique/jourCoût relatif de stockageRétention courante
Métriques~100 Mo – 1 GoFaible15 – 90 jours
Traces (échantillonnées)~500 Mo – 5 GoMoyen7 – 30 jours
Logs~1 – 50 GoÉlevé7 – 90 jours

Les logs parcourent un chemin en 4 étapes entre leur émission et le moment où un humain les consulte. Comprendre ce pipeline est essentiel pour savoir où agir sur le volume, le format et l’enrichissement.

  1. Émission

    L’application génère le log via une bibliothèque de logging (Python structlog, Java Logback, Go slog, Node.js pino). C’est à cette étape que le format (structuré ou non) et le niveau de sévérité sont décidés. En environnement conteneurisé, les logs sont émis sur stdout/stderr — le runtime (Docker, Kubernetes) les capture automatiquement.

  2. Collecte

    Un agent ou un collecteur récupère les logs depuis la source (fichier, stdout, socket syslog) et les transmet au stockage. Exemples : Promtail (pour Loki), Fluentd, Fluent Bit, OpenTelemetry Collector. C’est à cette étape qu’on peut filtrer, enrichir (ajouter des labels Kubernetes), transformer le format, et échantillonner ou limiter le débit (rate limit) des logs très fréquents pour maîtriser le volume.

  3. Stockage et indexation

    Le backend stocke les logs et les indexe pour permettre le requêtage. Deux approches existent : Elasticsearch indexe le contenu riche des logs (recherche plein texte puissante, mais coûteuse en stockage et en ressources). Loki optimise l’index sur des labels et s’appuie sur le scan du contenu au moment du requêtage — plus économique, mais les recherches dans le corps du message sont plus lentes sur de gros volumes.

  4. Requêtage et visualisation

    L’opérateur recherche dans les logs via un langage de requête (LogQL pour Loki, KQL pour Elasticsearch/Kibana) depuis une interface comme Grafana Explore. C’est à cette étape que la structure du log paie : un log JSON avec des champs nommés se filtre en secondes ; un log texte libre nécessite des regex lentes.

Le chemin que prend un log dépend de l’environnement d’exécution :

  • En conteneurs (Docker, Kubernetes) : l’application écrit sur stdout/stderr, le runtime capture les logs et un agent (Promtail, Fluent Bit, OTel Collector) les collecte
  • Sur VM / bare-metal : l’application écrit dans un fichier (.log), un agent le lit (tail) et le transmet
  • Syslog : l’application envoie sur une socket (UDP/TCP), rsyslog ou syslog-ng reçoit et route

Pipeline de collecte de logs : Application → Collecteur → Backend → Interface

Avant de déployer un service, vérifiez que vos logs cochent ces cases :

  • 1 événement = 1 log JSON — pas de logs multi-lignes (stack traces incluses dans un champ error.stack, pas étalées sur 30 lignes)
  • Timestamp UTC ISO 86012026-02-07T14:32:15.042Z, jamais l’heure locale
  • level calibré — pas de WARN partout, pas d’ERROR pour un cas nominal
  • service, version, environment renseignés — identifient précisément l’émetteur
  • trace_id et/ou request_id présents — permettent la corrélation
  • Aucun secret ni PII en clair — ni dans le message, ni dans les champs
  • Pas de payloads énormes — pas de body HTTP complets, pas de dumps d’objets
  • Message court et stable — les variables dans des champs dédiés
PiègePourquoi c’est un problèmeQue faire
Logger en texte libreImpossible à filtrer proprement, regex fragilesAdopter le JSON structuré avec des champs nommés
Oublier le trace_idLes logs sont isolés — pas de corrélation avec les tracesInjecter le trace_id via le contexte OpenTelemetry ou un middleware
Logger les corps de requêtesVolume énorme + risque PIILogger uniquement les métadonnées (méthode, path, status, durée)
Pas de convention de nommageuserId / user_id / UserID dans 3 services différentsDéfinir un schéma de nommage d’équipe (snake_case recommandé)
Ignorer la rétentionLes logs s’accumulent indéfiniment → coût explosifDéfinir une politique de rétention par niveau
Confondre log et métrique”Compter les erreurs via grep” est lent et imprécisLes compteurs appartiennent aux métriques, pas aux logs
  • Un log est un événement discret et horodaté — il capture le détail individuel, contrairement à la métrique qui agrège.

  • Un log structuré (JSON avec des champs nommés) est interrogeable par une machine ; un log texte libre ne l’est que par grep.

  • Les 6 champs essentiels sont : timestamp (UTC, ISO 8601), level, service, message, trace_id, request_id.

  • Les niveaux de sévérité (DEBUG → INFO → WARN → ERROR → FATAL) sont un engagement envers l’équipe d’astreinte : un ERROR doit toujours mériter une investigation.

  • Ne jamais logger de secrets, de PII en clair ni de données financières complètes.

  • Les logs sont le signal le plus cher : le volume en production doit être maîtrisé (pas de DEBUG permanent, rétention adaptée).

  • Le pipeline émission → collecte → stockage → requêtage est la chaîne à optimiser. La qualité du log se décide à l’émission, pas au requêtage.

Ce site vous est utile ?

Sachez que moins de 1% des lecteurs soutiennent ce site.

Je maintiens +700 guides gratuits, sans pub ni tracing. Aujourd'hui, ce site ne couvre même pas mes frais d'hébergement, d'électricité, de matériel, de logiciels, mais surtout de cafés.

Un soutien régulier, même symbolique, m'aide à garder ces ressources gratuites et à continuer de produire des guides de qualité. Merci pour votre appui.