Skip to Content

Chapitre 14.1 — Les logs, ta boîte noire

⏱️ TL;DR — Un serveur qui tourne écrit en permanence ce qu’il fait : chaque démarrage de service, chaque requête HTTP, chaque tentative de connexion SSH, chaque erreur. Ces logs sont ta boîte noire : quand ça casse, ils te disent quoi, quand et pourquoi. Deux mondes cohabitent sur une Ubuntu moderne : le journal systemd (interrogé avec journalctl) pour les services, et les fichiers texte de /var/log (syslog, auth.log, les logs Nginx). Tu vas apprendre à les lire efficacement (suivre en direct, filtrer, remonter dans le temps) et — crucial — à les faire tourner avec logrotate, parce qu’un log qu’on ne borne pas remplit le disque et fait tomber toute la machine.

🎯 Objectifs

  • Interroger le journal systemd avec journalctl : par service, en direct, par période, par niveau de gravité.
  • Connaître les fichiers de log clés de /var/log et ce qu’ils contiennent.
  • Lire efficacement un log : tail -f, grep, less.
  • Mettre en place la rotation des logs avec logrotate pour ne jamais saturer le disque.
  • Comprendre les niveaux de log et survoler la centralisation.

Deux endroits où vivent les logs

Sur une Ubuntu/Debian moderne, tes logs se trouvent à deux endroits complémentaires, et il faut savoir naviguer entre les deux.

  • journald (le journal de systemd) collecte les sorties de tous les services gérés par systemd, plus les messages du noyau. On l’interroge avec journalctl. C’est structuré, indexé, requêtable.
  • /var/log contient les fichiers texte classiques, hérités d’Unix : le syslog général, auth.log (authentification), et surtout les logs de tes applications tierces comme Nginx (access.log, error.log), qui écrivent directement dans leurs propres fichiers.

Le journal systemd : journalctl

C’est ton point de départ pour tout ce qui est service. Ton app Next.js, ton API Symfony, Nginx (au niveau du service), Postgres : tout ce qui tourne en unit systemd remonte ici.

🐚 Au terminal — Les incantations journalctl que tu taperas tous les jours :

# Les logs d'UN service précis (le drapeau -u = unit) journalctl -u formacampus-web # Suivre en DIRECT (le drapeau -f = follow), comme tail -f journalctl -u formacampus-web -f # Depuis une période (le langage est naturel) journalctl -u formacampus-web --since "1 hour ago" journalctl -u formacampus-web --since "2026-07-15 09:00" --until "2026-07-15 10:00" # Ne garder que les erreurs (le drapeau -p err = priorité >= error) journalctl -u formacampus-web -p err # Les logs depuis le DERNIER démarrage de la machine (le drapeau -b = boot) journalctl -b # Le boot précédent (utile après un reboot inattendu) journalctl -b -1

Décortiquons les options, car ce sont elles qui rendent journalctl puissant :

  • -u <service> cible un service précis. Sans ça, tu vois tout, c’est illisible. C’est ton premier réflexe : « qu’est-ce que dit ce service ? ».
  • -f (follow) affiche les nouvelles lignes en temps réel. Tu le lances, tu recharges la page en erreur dans ton navigateur, et tu regardes l’erreur apparaître. Indispensable pour reproduire un bug.
  • --since / --until bornent la fenêtre temporelle. « Le site a ramé vers 9 h » → tu regardes précisément ce créneau au lieu de scroller des heures.
  • -p err filtre par priorité (gravité). Tu ne vois que les messages de niveau error et au-dessus, en ignorant le bruit informatif. On y revient plus bas avec les niveaux.
  • -b limite au démarrage courant de la machine. Après un reboot surprise, journalctl -b -1 te montre les derniers soubresauts avant le crash.

💡 Réflexe — Face à un service qui déraille, l’enchaînement gagnant est toujours le même : systemctl status <service> pour l’état résumé, puis journalctl -u <service> -p err --since "30 min ago" pour lire précisément les erreurs récentes de ce service. Deux commandes, et tu sais.

📚 La doc — Tape man journalctl : la liste des filtres est longue (par PID, par utilisateur, par exécutable, en JSON avec -o json…). Le man fait autorité, les options évoluent peu.

Les logs classiques de /var/log

Tout ne passe pas par journald. Beaucoup de logiciels écrivent directement dans des fichiers. Les incontournables :

FichierContenu
/var/log/syslogLe journal général du système (services, cron, divers).
/var/log/auth.logLes authentifications : connexions SSH, sudo, su.
/var/log/nginx/access.logChaque requête HTTP reçue par Nginx (IP, URL, code, taille).
/var/log/nginx/error.logLes erreurs de Nginx (502, upstream injoignable, config).

Le fichier auth.log mérite une attention particulière. Ouvre-le sur un serveur exposé depuis quelques jours et tu verras des centaines de tentatives de connexion SSH échouées, depuis le monde entier : ce sont des bots qui bruteforcent en permanence. C’est normal et ça confirme pourquoi tu as désactivé le mot de passe SSH et installé fail2ban (Partie 5).

🔒 Sécuritéauth.log est ta caméra de surveillance de l’accès au serveur. Une rafale de Failed password depuis une IP, c’est un bruteforce (fail2ban devrait la bannir). Mais un Accepted publickey que tu n’as pas initié, ou un sudo inattendu, c’est un signal d’alerte majeur. Regarder auth.log régulièrement — ou mieux, y brancher une alerte (chapitre 14.3) — fait partie de l’hygiène de prod.

Les logs Nginx, eux, sont ta source de vérité sur le trafic : qui vient, sur quelles URL, avec quels codes de réponse. On s’en resservira au chapitre 14.4 pour calculer un taux d’erreur 5xx.

Lire efficacement un log

Un fichier de log de production fait vite des dizaines de milliers de lignes. On ne l’ouvre pas en entier. Trois outils suffisent :

# Suivre en direct les nouvelles requêtes (le -f = follow) tail -f /var/log/nginx/access.log # Les 100 dernières lignes seulement tail -n 100 /var/log/nginx/error.log # Filtrer : ne montrer que les lignes contenant "500" grep " 500 " /var/log/nginx/access.log # Combiner : suivre en direct MAIS seulement les erreurs 5xx tail -f /var/log/nginx/access.log | grep " 50" # Parcourir un gros fichier confortablement (navigation, recherche avec /) less /var/log/nginx/error.log
  • tail -f suit le fichier en direct : chaque nouvelle ligne s’affiche. C’est l’équivalent, pour les fichiers texte, du journalctl -f.
  • grep <motif> ne garde que les lignes qui contiennent le motif. « Montre-moi les 502 », « les requêtes de cette IP », « les erreurs d’hier ». C’est ton filtre universel.
  • less ouvre le fichier en lecture navigable (flèches, / pour chercher, G pour la fin, q pour quitter) sans tout charger en RAM. Parfait pour explorer un gros log posément.

💡 Réflexe — Le combo tail -f … | grep … est ton stéthoscope. Tu poses l’oreille sur le flux en direct, filtré sur ce qui t’intéresse (une IP, un code d’erreur, une URL), pendant que tu reproduis le problème dans le navigateur. L’erreur apparaît sous tes yeux, avec son horodatage exact.

La rotation des logs : logrotate

Voici le point qui sauve ta prod, et que les débutants ignorent jusqu’à la première panne.

Un log grandit sans fin. access.log prend quelques octets par requête ; multiplié par des millions de requêtes sur des mois, ça fait des gigaoctets. Si rien ne borne cette croissance, le fichier finit par remplir le disque. Et un disque plein, tu le sais depuis la Partie 1, c’est la panne totale : la base ne peut plus écrire, l’app tombe, plus rien ne fonctionne — une catastrophe qui semble « sortie de nulle part ».

La solution est logrotate : un outil (déjà présent sur Ubuntu, lancé quotidiennement) qui fait tourner les logs. Concrètement, il renomme le log courant, en ouvre un neuf, compresse les anciens et supprime les trop vieux. Tu gardes un historique utile sans croissance infinie.

⚠️ Piège — Le log qui remplit le disque en silence. C’est la panne la plus sournoise du débutant : tout marche pendant des semaines, puis un matin tout est mort, et la cause — un access.log ou un log applicatif de 40 Go — n’a aucun rapport apparent avec le symptôme (« le site ne répond plus »). Le pire ? Tes logs applicatifs maison (ton app qui écrit dans un fichier à elle) ne sont pas couverts par défaut : c’est à toi de leur écrire une règle logrotate.

Les paquets bien faits (Nginx, etc.) posent leur config dans /etc/logrotate.d/ — un fichier par logiciel. Pour ton propre log applicatif, tu ajoutes le tien. Un exemple commenté pour un log maison :

# /etc/logrotate.d/formacampus /var/log/formacampus/*.log { daily # tourner tous les jours rotate 14 # garder 14 archives (donc ~14 jours d'historique) compress # gzip les archives (elles pesent 10x moins) delaycompress # ne pas compresser la plus recente (encore ecrite) missingok # pas d'erreur si le fichier n'existe pas encore notifempty # ne pas tourner un fichier vide copytruncate # copier puis vider le fichier en place }
  • daily + rotate 14 : on tourne chaque jour et on conserve 14 archives. Au-delà, les plus vieilles sont supprimées automatiquement. C’est ta rétention : assez d’historique pour enquêter, pas assez pour saturer.
  • compress : les vieux logs sont gzippés, ce qui divise leur taille par dix environ. Un log texte se compresse remarquablement bien.
  • copytruncate est utile quand l’app garde le fichier ouvert en écriture : logrotate le copie puis le vide sur place, sans exiger que l’app rouvre son fichier. (Les daemons qui savent réouvrir sur signal utilisent plutôt create.)

🐚 Au terminal — Ne devine pas si ta règle marche, teste-la à sec :

# Simuler sans rien modifier (mode debug), voir ce que logrotate ferait sudo logrotate -d /etc/logrotate.d/formacampus # Forcer une rotation immédiate pour valider en vrai (-f = force) sudo logrotate -f /etc/logrotate.d/formacampus

Les niveaux de log

Un message de log a une gravité. La hiérarchie standard (syslog), du plus grave au plus anodin : emergency, alert, critical, error, warning, notice, info, debug. En pratique tu raisonnes surtout avec quatre d’entre eux : error (quelque chose a échoué), warning (anomalie non bloquante), info (fonctionnement normal), debug (détail verbeux, pour développer).

L’intérêt : filtrer. En prod, tu ne veux pas noyer le signal sous le debug. Le filtre -p err de journalctl ne montre que le niveau error et au-dessus. Côté application, tu règles le niveau de log de ton framework (souvent info en prod, debug seulement en cas d’enquête).

⚠️ Piège — Laisser le niveau debug actif en production. Non seulement ça noie les vraies erreurs dans un océan de détails, mais ça remplit le disque bien plus vite. En prod : info par défaut, debug seulement le temps d’une investigation, puis on revient à info.

Centralisation & persistance (survol)

Sur un seul VPS, lire les logs sur la machine suffit. Mais deux améliorations valent d’être connues.

Rendre journald persistant. Par défaut, sur certaines installations, le journal systemd est en mémoire et disparaît au reboot — gênant pour enquêter sur un crash. Pour le conserver sur disque, on crée /var/log/journal (et journald bascule en mode persistant) ; on borne alors sa taille dans /etc/systemd/journald.conf (SystemMaxUse) pour, encore une fois, ne pas remplir le disque.

Centraliser (survol). Dès que tu as plusieurs serveurs, aller lire les logs machine par machine devient pénible. On envoie alors les logs ailleurs, vers un collecteur central (des stacks comme Loki/Grafana, ou des services managés), pour tout chercher au même endroit. Sur un unique VPS FormaCampus, c’est prématuré ; on le garde en tête pour plus tard.

🧭 Sur FormaCampus — Sur le VPS de FormaCampus, l’équipe a posé une règle logrotate pour chaque log applicatif (front Next.js et API Symfony écrivent dans /var/log/formacampus/), avec rotate 14 et compress — après s’être fait peur une fois, quand un log de debug oublié avait grignoté le disque en une nuit. Le journald est passé en persistant et borné, pour pouvoir analyser un reboot inattendu. Et auth.log est surveillé : toute rafale suspecte déclenchera une alerte (chapitre 14.3). Résultat : les logs informent sans jamais menacer la machine.

✏️ Exercices

Exercice 1 — L’API renvoie des 500 depuis 10 minutes. Ton API Symfony tourne en service systemd nommé formacampus-api. Quelle(s) commande(s) tapes-tu pour voir précisément ce qui se passe, et pourquoi ces options ?

✅ Solution

D’abord l’état résumé : systemctl status formacampus-api (le service tourne-t-il, a-t-il redémarré ?). Puis les erreurs récentes de ce service : journalctl -u formacampus-api -p err --since "15 min ago". Le -u cible l’API (on ignore le reste), -p err ne garde que les erreurs (on écarte le bruit info), --since "15 min ago" borne à la fenêtre du problème. Pour voir l’erreur se produire en direct, on reproduit la requête en gardant ouvert journalctl -u formacampus-api -f.

Exercice 2 — Un log applicatif menace le disque. Ton app écrit dans /var/log/formacampus/app.log, qui grossit vite et n’est couvert par aucune rotation. Écris une règle logrotate qui tourne le log chaque jour, garde 7 jours d’historique, compresse les archives, et fonctionne même si l’app garde le fichier ouvert.

✅ Solution

Un fichier /etc/logrotate.d/formacampus-app :

/var/log/formacampus/app.log { daily rotate 7 compress delaycompress missingok notifempty copytruncate }

daily + rotate 7 = rotation quotidienne, 7 archives conservées (les plus vieilles supprimées). compress gzippe les archives. copytruncate copie puis vide le fichier en place, ce qui convient à une app qui garde son log ouvert sans savoir le réouvrir. On valide avec sudo logrotate -d /etc/logrotate.d/formacampus-app (simulation) puis -f (rotation forcée).

🧠 Quiz de révision

1. Quelle est la différence entre le journal systemd et les fichiers de /var/log ?

Le journal systemd (journald, lu avec journalctl) collecte de façon structurée et requêtable les sorties des services systemd et du noyau. Les fichiers de /var/log sont des logs texte classiques écrits directement par certains logiciels (Nginx, cron, auth.log…). On lit les premiers avec journalctl, les seconds avec tail/grep/less.

2. Que font les options -u, -f et -p err de journalctl ?

-u <service> cible un service précis. -f (follow) affiche les nouvelles lignes en temps réel. -p err filtre par priorité et ne garde que le niveau error et au-dessus (on écarte le bruit informatif).

3. Pourquoi la rotation des logs est-elle vitale, et avec quel outil ?

Parce qu’un log grandit sans fin et finit par remplir le disque, ce qui provoque une panne totale (la base et l’app ne peuvent plus écrire). L’outil est logrotate : il renomme le log, en ouvre un neuf, compresse les anciens et supprime les trop vieux, bornant ainsi la taille tout en gardant un historique.

4. Que surveille-t-on dans /var/log/auth.log ?

Les authentifications : connexions SSH (réussies et échouées), usages de sudo/su. On y repère les bruteforces SSH (rafales de Failed password) et surtout tout accès inattendu (Accepted publickey ou sudo qu’on n’a pas initié), signal de sécurité majeur.

5. Pourquoi éviter le niveau debug en production ?

Parce que debug noie les vraies erreurs sous un flot de détails et remplit le disque bien plus vite. En prod, on reste en info, et on n’active debug que temporairement, le temps d’une investigation, avant de revenir à info.


Chapitre suivant : Métriques système — mesurer l’état de la machine et trouver le goulot d’étranglement.

Last updated on