Stanotte il sito è andato giù per dieci minuti e nessuno sa perché? Un servizio non parte e il suo messaggio d'errore non compare da nessuna parte? Una copia di sicurezza è fallita e vuoi sapere quando? In tutti questi casi la risposta sta nei registri (in inglese log), il diario in cui il sistema annota tutto quello che accade. Sui sistemi moderni, lo strumento per leggerlo è journalctl.
Cos'è
Quasi tutte le distribuzioni oggi usano systemd (vedi l'articolo su systemctl), che comprende un servizio dedicato ai registri, systemd-journald. Raccoglie in un unico posto, il journal (il "giornale"), i messaggi del kernel, dei servizi, degli accessi e dei programmi lanciati dall'utente. A differenza dei classici file di testo in /var/log, il giornale è un archivio binario e indicizzato: non si legge con cat o less, ma con journalctl, che permette di cercare e filtrare in modo molto preciso.
Cosa fa
Legge il giornale e mostra le righe che interessano: quelle di un servizio, di un intervallo di tempo, di un certo livello di gravità, dell'avvio attuale o di uno precedente. Può anche restare in attesa e mostrare le righe nuove man mano che arrivano, e gestire lo spazio occupato dal giornale.
Come si usa
$ journalctl [opzioni] [filtri]Per leggere tutto il giornale servono i privilegi di amministratore (con sudo, vedi l'articolo relativo), oppure l'appartenenza a uno dei gruppi adm o systemd-journal (vedi l'articolo su id). Un utente normale vede solo i propri messaggi, e journalctl lo segnala con un avviso. Gli esempi usano il server web01 degli articoli precedenti: le righe dei registri sono illustrative, ma i comandi e i formati li ho provati su un giornale di prova.
Esempio 1: gli ultimi messaggi
$ journalctl -n 4
ott 31 23:10:01 web01 CRON[3790]: pam_unix(cron:session): session closed for user root
ott 31 23:12:08 web01 sshd[3811]: Accepted publickey for enzo from 203.0.113.45
ott 31 23:12:08 web01 systemd[1]: Started session-412.scope - Session 412 of User enzo.
ott 31 23:17:44 web01 sshd[3811]: pam_unix(sshd:session): session closed for user enzoCon -n 4 si vedono le ultime quattro righe (il numero si sceglie). Ogni riga ha lo stesso schema: data e ora, nome della macchina, programma con il suo numero di processo tra parentesi quadre, e il messaggio. Senza opzioni journalctl mostra tutto il giornale, dal più vecchio al più recente, in un lettore a pagine come less (vedi l'articolo relativo): premi q per uscire. Altri modi di partire dalla fine: -e (end) salta in fondo alla pagina, -r (reverse) mostra prima le righe più recenti.
Esempio 2: i messaggi di un servizio, con -u
$ journalctl -u nginx -n 3 -o cat
nginx: [emerg] bind() to 0.0.0.0:80 failed (98: Address already in use)
nginx.service: Control process exited, code=exited, status=1/FAILURE
nginx.service: Failed with result 'exit-code'.
$ journalctl -u nginx -u mariadb --since today
$ systemctl status nginx
$ journalctl -xeu nginxCon -u (unit) si legge solo ciò che riguarda un servizio, nel formato systemd che si usa con systemctl: l'esempio mostra un classico, un servizio che non parte perché la porta 80 è già occupata (per scoprire da chi, vedi lsof -i :80 nell'articolo relativo). Si possono indicare più servizi, ripetendo -u. Il flusso tipico quando un servizio non parte: systemctl status per vedere lo stato e le ultime righe, poi journalctl -xeu nome per i dettagli. L'opzione -x aggiunge, dove esistono, spiegazioni sul significato dei messaggi. Su alcune distribuzioni il nome del servizio SSH è ssh (Debian, Ubuntu), su altre sshd (Fedora, RHEL).
Esempio 3: un periodo di tempo preciso
$ journalctl --since "2026-10-31 02:00" --until "2026-10-31 03:00"
$ journalctl --since yesterday
$ journalctl --since "1 hour ago"
$ journalctl -S today -U now -u nginx
$ journalctl --since "2026-10-31 02:00" --until "+30 minutes"Con --since e --until (abbreviati -S e -U) si limita l'intervallo. Le date si scrivono nel formato AAAA-MM-GG HH:MM:SS oppure con parole inglesi: yesterday, today, now, "1 hour ago", "2 days ago". L'ora è quella locale del sistema. Quando qualcuno ti dice "il sito è andato giù stanotte verso le due", questo è lo strumento: restringi la finestra e leggi cosa è successo.
Esempio 4: gli avvii precedenti
$ journalctl --list-boots
IDX BOOT ID FIRST ENTRY LAST ENTRY
-2 9b8e7d6c.. sab 2026-09-12 06:39:15 CEST dom 2026-10-25 23:50:11 CET
-1 3c1f9a2e.. dom 2026-10-25 23:51:02 CET gio 2026-10-29 04:03:44 CET
0 5e7a1b4d.. gio 2026-10-29 04:04:10 CET dom 2026-11-01 05:27:29 CET
$ journalctl -b
$ journalctl -b -1 -p errIl giornale divide i messaggi per avvio del sistema. --list-boots elenca quelli registrati (gli identificativi qui sono accorciati): 0 è l'avvio attuale, -1 il precedente. -b mostra solo l'avvio attuale; -b -1 quello precedente, utile per capire perché la macchina si è riavviata o si è bloccata (vedi l'articolo su uptime): le ultime righe prima dello spegnimento dicono spesso la causa.
Esempio 5: solo i problemi, per gravità
$ journalctl -p err -b
ott 31 02:14:55 web01 kernel: Out of memory: Killed process 4410 (python3)
ott 31 06:00:02 web01 backup[3921]: rsync: connessione rifiutata da 192.168.1.20
$ journalctl -p warning..err --since yesterday
$ journalctl -p 3 -bOgni messaggio ha un livello di gravità, dal più grave al meno grave: emerg (0), alert (1), crit (2), err (3), warning (4), notice (5), info (6), debug (7). Con -p err si vedono i messaggi di quel livello e di quelli più gravi, e con un intervallo (warning..err) solo quelli compresi: il numero (-p 3) funziona come il nome. È il primo filtro da usare per ripulire il rumore: nell'esempio compaiono subito la memoria finita durante la notte (vedi l'articolo su free) e la copia di sicurezza fallita.
Esempio 6: seguire i messaggi in tempo reale
$ journalctl -f
$ journalctl -f -u nginx
$ journalctl -n 0 -f -t backupCon -f (follow) journalctl resta in attesa e mostra le righe nuove appena arrivano, come tail -f (vedi l'articolo su head e tail). Si ferma con Ctrl+C. È il modo più comodo di osservare un servizio mentre lo si riavvia o mentre si prova a riprodurre un errore: in una finestra il journalctl -f, nell'altra il systemctl restart. Con -n 0 si parte senza le righe precedenti, così compare solo ciò che accade da quel momento.
Esempio 7: cercare
$ journalctl -g 'rifiutata' --since yesterday
$ journalctl -t backup -b
$ journalctl _UID=1000 -p warning
$ journalctl /usr/sbin/sshd
$ journalctl -b | grep -i 'failed password'L'opzione -g (grep) cerca un'espressione nei messaggi: se il testo è tutto in minuscolo, ignora la differenza tra maiuscole e minuscole. Con -t (identifier) si seleziona il nome con cui un programma o uno script si presenta nel giornale (vedi l'esempio 10). Il giornale conosce anche molti campi interni, che si usano come filtri nel formato CAMPO=valore: _UID=1000 (l'utente), _PID=3811 (il processo), _COMM=nome (il comando). Se indichi il percorso di un programma (/usr/sbin/sshd), vedi tutti i suoi messaggi. L'ultimo comando mostra che journalctl si combina con grep e awk (vedi l'articolo su awk), perché stampa semplice testo quando l'output non è un terminale. Per i tentativi di accesso falliti vedi anche lastb nell'articolo su who.
Esempio 8: i messaggi del kernel
$ journalctl -k -b
$ journalctl -k -g 'out of memory'
$ journalctl -k -b -1 -p errCon -k (kernel) si leggono solo i messaggi del kernel, come con il comando dmesg, ma con il vantaggio di poter risalire anche agli avvii precedenti. Sono quelli in cui compaiono i problemi di disco (vedi gli articoli su lsblk e mount), di memoria finita (OOM killer, vedi l'articolo su free), di schede di rete e di dispositivi USB.
Esempio 9: i formati di output
$ journalctl -t backup -n 1 -o short-iso
2026-10-31T06:00:02+01:00 web01 backup[3921]: copia completata in 42 s
$ journalctl -t backup -n 2 -o cat
rsync: connessione rifiutata da 192.168.1.20
copia completata in 42 s
$ journalctl -t backup -n 1 -o json-pretty
{
"MESSAGE" : "copia completata in 42 s",
"PRIORITY" : "5",
"SYSLOG_IDENTIFIER" : "backup",
"_HOSTNAME" : "web01",
"_PID" : "3921",
"__REALTIME_TIMESTAMP" : "1793512802000000"
}L'opzione -o (output) cambia la forma. short-iso scrive la data in formato internazionale (utile negli script e per ordinare). cat mostra solo il testo del messaggio, senza data né nome: perfetto per copiare un errore o contare le righe. json e json-pretty producono un formato strutturato adatto ai programmi (con jq, o con uno script Python) ed espongono tutti i campi del messaggio: nell'esempio ne ho mostrati solo alcuni. verbose elenca tutti i campi in forma leggibile. Il campo PRIORITY è il livello di gravità dell'esempio 5 (5 è notice); __REALTIME_TIMESTAMP è la data in microsecondi dal 1970.
Esempio 10: scrivere nel giornale dai propri script
$ logger -t backup "copia completata in 42 s"
$ logger -t backup -p user.err "rsync: connessione rifiutata da 192.168.1.20"
$ journalctl -t backup -n 2
ott 31 06:00:01 web01 backup[3920]: copia completata in 42 s
ott 31 06:00:02 web01 backup[3921]: rsync: connessione rifiutata da 192.168.1.20Il comando logger scrive una riga nel giornale. Con -t si sceglie il nome con cui compare (l'identificatore), con -p il livello (user.err è un errore, user.notice un'informazione normale). Dentro uno script, al posto di un echo che finisce chissà dove (soprattutto con crontab, vedi l'articolo relativo), permette poi di ritrovare tutto con journalctl -t nome, con la data e il livello giusti.
Esempio 11: lo spazio occupato
$ journalctl --disk-usage
Archived and active journals take up 1.2G in the file system.
$ sudo journalctl --vacuum-size=500M
Vacuuming done, freed 640.0M of archived journals from /var/log/journal.
$ sudo journalctl --vacuum-time=1month
$ sudo nano /etc/systemd/journald.conf
[Journal]
Storage=persistent
SystemMaxUse=500M
MaxRetentionSec=1month
$ sudo systemctl restart systemd-journaldIl giornale cresce, e su un server molto attivo può occupare gigabyte (vedi gli articoli su df e du). --disk-usage dice quanto spazio usa; --vacuum-size e --vacuum-time eliminano i file più vecchi fino a rispettare un limite di dimensione o di età (non si torna indietro). Per un limite permanente si modifica /etc/systemd/journald.conf: SystemMaxUse è lo spazio massimo, MaxRetentionSec la durata massima di conservazione, e Storage=persistent chiede di conservare il giornale anche dopo il riavvio (vedi l'avvertenza qui sotto). Dopo la modifica si riavvia il servizio.
Esempio 12: uso negli script
#!/bin/bash
LOG="$HOME/controlli.log"
ERRORI=$(journalctl -t backup --since "24 hours ago" -p err -q --no-pager | wc -l)
if [ "$ERRORI" -gt 0 ]; then
echo "$(date '+%F') backup: $ERRORI errori nelle ultime 24 ore" >> "$LOG"
journalctl -t backup --since "24 hours ago" -p err -q --no-pager >> "$LOG"
fiLo script conta gli errori scritti dalla copia di sicurezza nelle ultime 24 ore (-p err prende solo gli errori, wc -l conta le righe: vedi l'articolo su wc) e, se ce ne sono, li copia in un file di controllo. Due opzioni utili negli script: --no-pager evita che journalctl apra il lettore a pagine, e -q (quiet) toglie gli avvisi informativi dall'output. Programmato con crontab ogni mattina, sostituisce il controllo a mano dei registri.
Opzioni utili
-u unità: i messaggi di un servizio;-t nome: quelli con un certo identificatore;-k: quelli del kernel.-b,-b -1,--list-boots: l'avvio attuale, il precedente, l'elenco degli avvii.-S/--since,-U/--until: intervallo di tempo.-p livello: gravità (err,warning,warning..err, 0-7).-g testo: cerca nei messaggi;CAMPO=valore: filtra per campo (_UID,_PID,_COMM).-n N: ultime N righe;-r: dal più recente;-e: salta in fondo;-f: segue in tempo reale;-x: aggiunge spiegazioni.-o formato:short-iso,cat,json,json-pretty,verbose;--no-pager,-q,--utc,--no-hostname.--disk-usage,--vacuum-size,--vacuum-time,--rotate,--verify: gestione dello spazio e controllo dei file.logger: scrive nel giornale;systemctl status: stato e ultime righe di un servizio;dmesg: messaggi del kernel.
Attenzione a
- Su molte installazioni il giornale non sopravvive al riavvio: con l'impostazione
Storage=autoil giornale viene salvato su disco solo se esiste la cartella/var/log/journal; altrimenti vive in memoria e si perde a ogni avvio. In quel casojournalctl -b -1risponde con un avviso (no persistent journal was found) e non mostra niente: proprio quando serviva capire cosa è successo prima di un blocco. Per conservarlo, impostaStorage=persistent(esempio 11) prima che serva. - Senza privilegi vedi solo una parte: un utente normale non vede i messaggi del sistema, e un "nessun risultato" può voler dire solo "non puoi vederlo". Usa
sudo, o aggiungi l'utente al grupposystemd-journal. journalctl -u nginxnon mostra i registri del sito: il giornale contiene ciò che il servizio scrive asystemd(avvio, arresto, errori di configurazione). I registri di accesso e degli errori dinginxo diApacherestano nei loro file, di solito sotto/var/log(come visto negli articoli sulsofetail).- Le righe lunghe vengono tagliate: nel lettore a pagine le righe più larghe dello schermo sono troncate. Scorri a destra con le frecce, oppure usa
--no-pagero-o cat, o manda l'output a un file. - L'ora è quella locale: se il server è in un altro fuso orario, o confronti registri di macchine diverse, aggiungi
--utc.--sincee--untilusano anch'essi l'ora locale. - Un messaggio non è una prova: se un sistema viene compromesso, i registri possono essere alterati o cancellati (come per
whoelast). Inviarli a una macchina separata è l'unico modo di avere un registro affidabile. - I limiti di frequenza: se un servizio scrive troppo velocemente,
journaldscarta alcuni messaggi, segnalandolo con una riga tipo "Suppressed N messages". Per un registro completo di un programma molto loquace conviene che scriva nei propri file. --vacuumcancella per sempre: non c'è cestino. Prima di ridurre il giornale, copia le parti che ti servono (per esempio conjournalctl ... > file.txt).- I registri contengono dati personali: indirizzi IP, nomi utente, orari di accesso. Non incollarli così come sono in forum o segnalazioni pubbliche, e conservali solo per il tempo necessario (
MaxRetentionSecaiuta a rispettarlo). - Non è il solo posto: i sistemi senza
systemd(e alcuni container) non hannojournalctl; su molte distribuzioni convivono anche i file di testo tradizionali (/var/log/syslog,/var/log/auth.log), che si leggono conlessegrep.
Riepilogo
| Comando | Cosa fa |
|---|---|
journalctl -n 20 | Ultime 20 righe |
journalctl -u nginx | Messaggi di un servizio |
journalctl -xeu nginx | Servizio, con spiegazioni, partendo dalla fine |
journalctl --since "1 hour ago" | Solo l'ultima ora |
journalctl -b / -b -1 | Avvio attuale / precedente |
journalctl --list-boots | Elenco degli avvii registrati |
journalctl -p err -b | Solo errori (e più gravi) dall'avvio |
journalctl -f | Segue i messaggi in tempo reale |
journalctl -g testo | Cerca un testo nei messaggi |
journalctl -k | Solo i messaggi del kernel |
journalctl -o cat / -o json-pretty | Cambia il formato di output |
logger -t nome "testo" | Scrive una riga nel giornale |
journalctl --disk-usage | Spazio occupato dal giornale |
sudo journalctl --vacuum-size=500M | Riduce il giornale a 500 MB |