Il y a des jours où tu ouvres un log système, tu fais défiler trois secondes, et tu sens déjà ton cerveau partir en fumée.
Des lignes à rallonge. Des timestamps partout. Des champs que tu n’as jamais demandés. Et au milieu, ton vrai problème, planqué comme une aiguille dans une botte de JSON.
Moi, ça m’arrive souvent quand je bosse sur un serveur Linux un peu vivant (un reverse proxy, un service systemd maison, un conteneur, un agent de monitoring, etc.). Et c’est exactement là que ce pipeline m’a sauvé plus d’une fois :
journalctl pour récupérer, filtrer, borner le temps.
jq pour rendre ça lisible, trier, extraire, colorer mentalement.
On va faire simple, pratique, et directement réutilisable.
Pourquoi journalctl est à la fois génial… et pénible
journalctl c’est super parce que :
- tout est là (systemd, kernel, services, boots)
- tu peux filtrer par service, par période, par priorité
- tu peux exporter en JSON
Mais c’est pénible parce que, par défaut, tu lis des logs comme un humain en 1987. Et quand tu as des messages applicatifs au format JSON dans le champ MESSAGE, tu te retrouves avec du JSON dans une ligne, dans un autre format, avec l’habillage systemd autour. Donc double illisibilité.
L’idée ici, c’est de sortir proprement les événements en JSON depuis journald, puis de laisser jq faire le boulot.
Le premier réflexe : sortir du JSON exploitable
La base, c’est ça :
bash journalctl -u monservice -o json
Sauf que -o json sort un objet JSON par ligne, et jq adore ça. Donc on enchaîne :
bash journalctl -u monservice -o json | jq .
Bon. C’est déjà mieux.
Mais tu vas vite vouloir :
- limiter à la session courante
- borner une période
- ne pas te taper 200 000 lignes
- n’afficher que certains champs
On arrive au vrai pipeline.
Le pipeline « qui sauve » pour un service systemd
Celui que je retape tout le temps, en mode squelette :
bash journalctl -u monservice --since "1 hour ago" -o json
| jq -r '{ts: .__REALTIME_TIMESTAMP, lvl: .PRIORITY, msg: .MESSAGE}'
Ça donne un JSON réduit. Mais les timestamps journald sont en microsecondes depuis epoch, pas directement lisibles. Donc on va convertir.
Conversion du timestamp journald en date lisible
jq peut faire ça, mais on doit diviser par 1 000 000.
bash journalctl -u monservice --since "1 hour ago" -o json
| jq -r ' .__REALTIME_TIMESTAMP as $t | { time: ($t | tonumber / 1000000 | todateiso8601), host: ._HOSTNAME, unit: ._SYSTEMD_UNIT, pid: ._PID, prio: .PRIORITY, msg: .MESSAGE } '
Déjà là, tu as quelque chose de « humain ».
Astuce : afficher en format texte propre (et pas du JSON)
Parfois tu ne veux pas du JSON. Tu veux juste lire vite.
bash journalctl -u monservice --since "2 hours ago" -o json
| jq -r ' .__REALTIME_TIMESTAMP as $t | "($t|tonumber/1000000|todateiso8601) [prio:(.PRIORITY)] pid=(._PID) (.MESSAGE)" '
Là tu as une sortie lisible, prête à scroller.
Filtrer par niveau de logs (priorité)
journald encode PRIORITY de 0 à 7. En gros :
- 0 à 3 : erreurs graves
- 4 : warning
- 5 : notice
- 6 : info
- 7 : debug
Filtrer sur les erreurs et warnings :
bash journalctl -u monservice --since "24 hours ago" -o json
| jq -r 'select(.PRIORITY|tonumber <= 4) | .MESSAGE'
Ça, c’est le genre de truc qui te fait gagner 20 minutes direct.
Quand le MESSAGE est lui-même du JSON
Cas très courant : ton appli logge un objet JSON dans MESSAGE.
Exemple, MESSAGE contient un truc du genre :
json {"level":"error","requestId":"abc","path":"/api","status":500,"err":"db timeout"}
Dans ce cas, tu peux parser le MESSAGE comme JSON dans jq.
bash journalctl -u monservice --since "1 hour ago" -o json
| jq -r ' .MESSAGE as $m | (try ($m|fromjson) catch null) as $mj | select($mj != null) | "($mj.level) ($mj.status) ($mj.path) requestId=($mj.requestId) ($mj.err)" '
Et là, magie. Tu lis enfin ce que ton app raconte, sans le bruit autour.
Repérer un pattern : grep, oui… mais mieux
Tu peux faire grep, mais autant rester dans jq quand tu es déjà en JSON.
Filtrer les messages qui contiennent « timeout » :
bash journalctl -u monservice --since "6 hours ago" -o json
| jq -r 'select(.MESSAGE|test("timeout"; "i")) | .MESSAGE'
Filtrer sur un champ JSON interne (si MESSAGE est JSON) :
bash journalctl -u monservice --since "6 hours ago" -o json
| jq -r ' .MESSAGE as $m | (try ($m|fromjson) catch null) as $mj | select($mj != null and ($mj.status|tostring) == "500") | $mj '
Oui, tu peux sortir l’objet entier. Et ensuite tu continues à filtrer.
Limiter le volume : tail et boots
Deux commandes que j’utilise en réflexe.
Derniers événements seulement
bash journalctl -u monservice -n 200 -o json | jq -r '.MESSAGE'
Depuis le dernier boot
bash journalctl -u monservice -b -o json | jq -r '.MESSAGE'
Et si tu veux lister les boots :
bash journalctl --list-boots
Puis :
bash journalctl -u monservice -b -1 -o json | jq -r '.MESSAGE'
Cas sysadmin réel : identifier un pic d’erreurs par minute
Tu as une avalanche d’erreurs, tu veux savoir quand ça a commencé, et si ça se calme.
On peut regrouper par minute.
bash journalctl -u monservice --since "2 hours ago" -o json
| jq -r ' select(.PRIORITY|tonumber <= 4) | (.__REALTIME_TIMESTAMP|tonumber/1000000) as $s | ($s - ($s % 60) | todateiso8601) '
| sort
| uniq -c
| sort -nr
| head
Ce n’est pas le pipeline le plus « beau », mais il est efficace. Tu obtiens un top des minutes les plus chargées en erreurs.
Bonus : extraire des champs journald utiles
Quelques champs pratiques que tu peux afficher sans te poser de questions :
._SYSTEMD_UNIT: le service._COMM: nom de la commande._EXE: chemin binaire._PID: pid._UID: user id._GID: group id._HOSTNAME: hostname.SYSLOG_IDENTIFIER: ident syslog si présent
Exemple :
bash journalctl -u monservice --since "1 day ago" -o json
| jq -r ' "(.SYSLOG_IDENTIFIER // "-") (. _SYSTEMD_UNIT // "-") pid=(._PID // "-") (.MESSAGE)" '
Petit détail : dans l’exemple ci dessus, je montre l’idée du fallback // "-". Selon les logs, certains champs peuvent être absents.
Mon « alias » perso (à copier)
Parce que oui, retaper ces options, c’est chiant.
Dans ~/.bashrc ou ~/.zshrc :
bash alias jql='journalctl -o json | jq -r'
Ensuite :
bash jql '"(.MESSAGE)"'
Ou pour un service :
bash journalctl -u monservice --since "30 min ago" -o json | jq -r '"(.MESSAGE)"'
Tu peux aussi faire un alias plus spécifique :
bash alias jerr='jq -r "select(.PRIORITY|tonumber<=4) | .MESSAGE"'
Et donc :
bash journalctl -u monservice --since "2 hours ago" -o json | jerr
Ça devient fluide. Et ça compte, surtout quand tu es en prod et que tu veux juste comprendre vite.
Petites erreurs classiques (et comment éviter de tourner en rond)
-
Tu oublies
-o json
jq ne peut pas parser une sortie texte journald. Donc-o jsonquasi obligatoire ici. -
Tu as des logs tronqués
Ajoute-lou--fullselon le besoin. Perso je fais souvent :bash journalctl -u monservice --since "1 hour ago" --no-pager --output=json --all
Le
--no-pagerévite le scroll via less. Pratique dans des scripts. -
MESSAGE n’est pas toujours du JSON
D’où letry ... catchdans jq. Sinon ton pipeline casse à la première ligne non JSON.
Conclusion rapide (et vraiment utilisable)
Si tu devais ne garder qu’un seul truc de cet article, garde ce réflexe :
journalctlen JSONjqpour extraire ce que tu veux- et si ton MESSAGE est JSON, tu le parses avec
fromjson
C’est littéralement ce qui transforme un mur de logs en quelque chose que tu peux lire, comprendre, et agir.
Si tu veux d’autres articles du même style, côté Linux, productivité et un peu business aussi quand même, passe faire un tour sur Le Blog Tech Pro de Samyn-Antoy ABASSE : Le Blog Tech Pro. J’y poste régulièrement des workflows concrets, pas des trucs théoriques qu’on oublie.
En parlant de trucs concrets, si tu cherches des commandes Linux qui sauvent, ou encore des [certifications Linux qui boostent](https://mon
Questions fréquemment posées
Pourquoi utiliser journalctl pour analyser les logs système sous Linux ?
Journalctl est un outil puissant car il centralise tous les logs (systemd, kernel, services, boots), permet de filtrer par service, période ou priorité, et offre une exportation en JSON, facilitant ainsi l'analyse des événements système.
Comment rendre les logs JSON de journalctl plus lisibles ?
En combinant journalctl avec jq : on récupère les logs au format JSON avec 'journalctl -o json' puis on utilise jq pour trier, extraire et colorer les informations importantes, ce qui améliore grandement la lisibilité.
Comment filtrer les logs d'un service systemd sur une période donnée ?
Utilisez le paramètre '--since' de journalctl, par exemple '--since "1 hour ago"' pour limiter les logs à la dernière heure. Ensuite, vous pouvez combiner cela avec jq pour extraire uniquement les champs souhaités.
Comment convertir le timestamp microseconde de journald en date lisible ?
Dans jq, divisez le champ __REALTIME_TIMESTAMP par 1 000 000 puis utilisez la fonction 'todateiso8601'. Par exemple : '. as $t | ($t|tonumber/1000000|todateiso8601)' permet d'obtenir une date au format ISO 8601 lisible.
Comment filtrer les logs par niveau de priorité avec journalctl et jq ?
Le champ PRIORITY varie de 0 à 7 (0-3 erreurs graves, 4 warning, etc.). Pour afficher seulement erreurs et warnings, filtrez avec jq comme ceci : 'select(.PRIORITY|tonumber <= 4)'. Cela réduit efficacement le volume des logs à analyser.
Que faire quand le champ MESSAGE contient lui-même un JSON ?
Avec jq, vous pouvez parser le contenu JSON du champ MESSAGE en utilisant 'fromjson'. Par exemple : '.MESSAGE as $m | (try ($m|fromjson) catch null) as $mj | select($mj != null)' permet d'extraire proprement les données imbriquées pour une analyse détaillée.
0 Commentaires