Guillaume Fenollar DevOps et SysAdmin Freelance

Guillaume FENOLLAR

Administrateur Linux | DevOps Indépendant

− Nouméa −

Introduction à Journald et Journalctl

Avec Systemd comme init system sur une grande majorité des distributions Linux les plus courantes, est venu également tout un tas d'outils et démons fournis avec le paquet original de systemd. Certains peuvent être ignorés, comme le module Timer, et certains sont incontournables, comme Journald, qui fait l'objet de cet article.

Journald est donc utilisé par défaut sur tout système utilisant Systemd comme init. Dans les faits, cela veut dire que toute application démarrée grâce à une commande systemctl voit ses logs stockés dans journald. Bien sûr, il s’agit ici seulement des logs écrits sur la sortie standard (stdout) et son équivalent pour les erreurs (stderr). Chaque application est bien entendu tout à fait capable d’écrire du log où bon lui semble sans que ce soit accessible via journald. Également, beaucoup d’autres logs continuent d’être écrits dans /var/log sur une distrib standard, comme par exemple Postfix, qui écrit à la fois dans journald, et dans /var/log, mais deux types d’informations différentes. Si vous ne trouvez rien dans /var/log concernant votre application, qui a été lancée via systemd, alors ses logs sont probablement stockés dans journald.

Personnellement, j’utilise énormément journald car me sert de systemd pour lancer mes conteneurs Docker standalone, comme expliqué dans cet article : https://guillaume.fenollar.fr/blog/systemd-gerer-lancer-conteneur-docker/, que je vous invite à consulter si vous vous intéressez aux conteneurs.

Première chose à savoir concernant journald, c’est qu’il est par défaut configuré pour garder ses journaux en mémoire, ce qui allège la pression sur le disque mais a plusieurs gros désavantages:

  • Perte des logs en cas de reboot ou crash de la machine.
  • Utilisation de la RAM (jusqu’à 10% par défaut), ce qui en enlève autant de disponible pour les applications critiques du serveur.

Évidemment tout ceci, comme tout ce qui va suivre, se configure facilement via un fichier de configuration, /etc/systemd/journald.conf.

Journald.conf

Voici tout d’abord le contenu de ce fichier avec les valeurs par défaut.

[Journal]
Storage=auto
Compress=yes
Seal=yes
SplitMode=uid
SyncIntervalSec=5m
RateLimitIntervalSec=30s
RateLimitBurst=1000
SystemMaxUse=
SystemKeepFree=
SystemMaxFileSize=
SystemMaxFiles=100
RuntimeMaxUse=
RuntimeKeepFree=
RuntimeMaxFileSize=
RuntimeMaxFiles=100
MaxRetentionSec=
MaxFileSec=1month
ForwardToSyslog=yes
ForwardToKMsg=no
ForwardToConsole=no
ForwardToWall=yes
TTYPath=/dev/console
MaxLevelStore=debug
MaxLevelSyslog=debug
MaxLevelKMsg=notice
MaxLevelConsole=info
MaxLevelWall=emerg

Ce qui détermine où sont écrits les logs, c’est la ligne Storage. Par défaut (quand cette ligne est commentée), sa valeur est à “auto”, mais elle peut prendre quatre valeurs:

  1. volatile : Les logs sont gardés dans la mémoire, plus précisément stockés dans le dossier /run/log/journal
  2. persistent : Les logs sont écrits sur le disque, dans le dossier /var/log/journal, à la condition que /var soit monté.
  3. auto (par défaut) : Le système choisit où sont écrits les logs. Si le dossier /var/log/journal existe et est accessible, alors les logs y seront écrits. Sinon, ça se fera en mémoire.
  4. none : Les logs ne sont pas stockés et donc directement droppés à la réception

Je conseille donc de le passer à pesistent. Comme écrit ci-dessus, il suffit également de créer le dossier /var/log/journal et de redémarrer le service systemd-journald pour ce soit pris en compte.

systemctl restart systemd-journald

D’autres paramètres intéressants sont les *MaxUse, *KeepFree, *MaxFile. Ils ont comme préfix soit System, soit Runtime. Dans le premier cas ils concernent le stockage persistant (sur disque donc), et dans le deuxième le stockage en RAM (qui ne nous intéresse plus ici).

  • SystemMaxUse : L’espace maximum utilisé par journald. Par défaut à 10% de l’espace total de la partition où sont stockés les fichiers (par exemple /var/), la valeur du fichier de configuration ne peut malheureusement être qu’une valeur absolue, impossible donc de spécifier “20%”, mais plutôt 5G, 900M, etc…
  • SystemKeepFree : L’espace qui doit rester libre sur la partition où sont trouvés les journaux. Par défaut 15%, ce qui veut dire qu’à 85% d’espace utiliser, journald supprimera des logs pour éviter de remplir la partition. Comme pour MaxUse, se remplace par une valeur absolue.
  • SystemMaxFileSize : Journald écrit ses fichiers au format binaire (non lisibles par un éditeur de texte), et fait une rotation sur ces fichiers. Le fichier en cours d’écriture sera rempli jusqu’à la taille spécifiée, avant qu’un nouveau fichier soit créé. Par défaut 18 de la taille totale définie avec SystemMaxUse. Par exemple, si vous définissez un SystemMaxUse de 1G, chaque fichier de journal sur disque fera au maximum 125M avant rotation.

Une fois la limite spécifiée à SystemMaxUse atteinte (je rappelle que cette valeur n’est utilisée seulement si le dossier /var/log/journal est présent ou si Storage est défini à persistent), le fichier de journal le plus vieux est supprimé.

La commande journalctl

Journalctl permet d’intéragir avec le démon system-journald. Parmi les arguments les plus courants à se souvenir impérativement, -u permet de spécifier l’unit (comprendre le service) à la source des logs désirés, -e permet d’afficher les 1000 dernières lignes de logs, -f permet de “follow” le flux de logs d’une application à la manière d’un tail -f, -p filtre sur un niveau de log défini (de 0, “emerg”, à 7, “debug”) augmentant ou diminuant la verbosité. Car en effet, la grande force de journald sur un stockage texte standard c’est que chaque message est enregistré avec une foule de métadonnées permettant de filtrer et cibler l’information rechercher efficacement. Par exemple, il est possible de spécifier une date précise de récupération de logs :

journalctl -u nginx --since yesterday
journalctl -u nginx --until "2018-09-27 15:16:23"
journalctl -u nginx --since "2018-09-15" --until "2018-09-16"

Des exemples valant parfois mieux qu’un long article, je vais conclure sur une mini cheat-sheet des commandes journalctl.

Cheat-Sheet

journalctl -u nginx -n 5000 → Affiche les 5000 lignes de logs de nginx dans un pager en commencant par les plus anciennes
journalctl --disk-usage →  Affiche l'espace couramment utilisé par les fichiers journaux du système
journalctl --vaccum-size 1G →  Nettoie les fichiers journaux pour ne garder qu'un gigaoctet d'utilisé
journalctl -eu nginx →  Affiche sous forme de pager les 1000 dernières de logs du service nginx
journalctl -fu nginx →  Affiche les toutes dernières lignes de log en continu
journalctl -k -p warning → Affiche seulement les messages d'alerte du kernel. L'option `p` ne fonctionne que si l'application les écrivant est compatible journald car les loglevels ne viennent pas de nul part
journalctl -p 2 →  Affiche les évenements critiques propres à toutes les applications gérant les loglevel
journalctl -u nginx --until yesterday →  N'affiche pas les messages nginx d'aujourd'hui
journalctl -o json →  Affiche le journal système global au format json, pratique pour découvrir toutes les champs (et leur contenu), et ainsi pouvoir scripter une analyse de logs efficace grâce à par exemple un script python