Sur une machine Debian GNU/Linux, je constate que /var/log/journal occupe 4,7 Go. Il s'agit du répertoire dans lequel systemd-journald range les journaux. Pour rappel, dans la conf' par défaut de Debian, journald envoie les journaux à rsyslog et en garde une copie au format binaire.
Lire le contenu d'un journal précis : journalctl --file /var/log/journal/chemin/vers/fichier.journal
. (Rigolo : strings
fonctionne aussi, mais avec du bruit, forcément. :D)
Il s'agit donc de la sortie du script « update_daemon2.php » de mon agrégateur de flux RSS, Tiny Tiny RSS (tt-rss), qui est lancé par systemd-systemd. Il récupère les flux RSS en quasi permanence afin de les actualiser (la périodicité dans les paramètres, 15 minutes par exemple, ne signifie pas que tous les flux seront récupérés en même temps toutes les 15 minutes, tt-rss dilue la récupération dans le temps, d'où ce n'est pas un CRON mais un processus).
Un détail : j'ai configuré rsyslog pour ranger cette sortie dans un fichier plat. Cela produit environ 200 Mo de journal par mois. Pour le même usage, journald crée un fichier de 128 Mo tous les deux jours. Le contenu est identique. journald stocke des métadonnées supplémentaires (on le voit avec strings
), et j'imagine que le format binaire est plus gourmand. Du coup, ça explique les 4,7 Go.
Le fichier journal le plus vieux date de fin octobre, donc ce n'est pas un problème de purge automatique.
On peut demander à journald de purger les journaux archivés (pas le journal en cours, mais on peut demander à journalctl archiver ce dernier au préalable avec un --rotate
) : journalctl --vacuum-time=X
= purger les entrées plus vieilles que X (exemple : X = « 7d » = une semaine) ; --vacuum-files
= purger la totalité du journal jusqu'à ce qu'il reste moins de X fichiers journaux ; --vacuum-size
= purger jusqu'à ce que la totalité du journal occupe moins que l'espace disque spécifié.
Mais cela purge l'ensemble des journaux archivés (peu importe le service, etc.), ce que je ne veux pas. Je n'ai pas trouvé d'option permettant de purger uniquement une unité spécifique, un fichier spécifique. Dans mon cas, le nom des fichiers journaux problématique est de la forme « user-1000@<UUID>.journal », car le script ttrss est exécuté avec cet utilisateur (dont l'UID est 1000).
Toute façon, cela ne serait pas une solution de long terme (le problème reviendrait).
Dans l'unit, j'ai ajouté une redirection vers le fichier journal dans « ExecStart ». systemctl daemon-reload
et restart du service tt-rss. Mais journald reçoit encore le journal, je le vois dans systemctl status unit
et avec journalctl --file
(on peut reconnaître le journal actuel / en cours par l'absence d'UUID dans son nom).
Dans la section « [Service] », on peut ajouter « StandardOutput=null » et « StandardError=null » (source), mais cela désactive toute journalisation (rsyslog ne reçoit plus rien), ce que je ne veux pas.
En consultant les valeurs possibles pour ces deux paramètres, je trouve « StandardOutput=append:/chemin/vers/fichier ». Cela fait le job : le fichier journal se remplit, journald reçoit plus rien.
Puisque ce n'est plus rsyslog qui journalise, je dois adapter ma configuration de logrotate.
Désormais, puisque le service est un script PHP, c'est l'interpréteur PHP en mode CLI qui détient le descripteur de fichier du journal (cela se vérifie avec lsof </chemin/vers/fichier/journal>
). PHP n'a pas de mécanisme pour libérer un descripteur de fichier (comme un signal, etc.). Redémarrer le service m'ennuie, même si, dans le cas d'espèce, ça répondrait au besoin.
C'est le moment de se souvenir que logrotate propose un mode adapté : « copytruncate » (il ne déplace pas le fichier journal, il le copie avant de vider le fichier original, ainsi l'inode ne change pas, le descripteur non plus). \o/