Salta al contenuto principale

dmesg: leggere i messaggi del kernel

Inviato da tuxsa il

Una chiavetta USB non compare, un disco rallenta all'improvviso, un processo sparisce senza lasciare traccia: la spiegazione è spesso in una riga scritta dal kernel, e quella riga non è in nessun file di log dei programmi. Si legge con dmesg, il primo comando da provare quando qualcosa va storto "sotto" il sistema.

Cos'è

dmesg (display message, o diagnostic message) fa parte del pacchetto util-linux, come lscpu, lsblk e mount. Il kernel (vedi l'articolo su uname) scrive tutto quello che gli succede in un'area di memoria circolare, il kernel ring buffer: l'avvio, i dispositivi riconosciuti, i driver caricati, gli errori dei dischi e della rete. "Circolare" vuol dire che ha una dimensione fissa e, quando è piena, i messaggi più vecchi vengono sovrascritti da quelli nuovi. dmesg legge questo buffer e lo mostra.

Cosa fa

Mostra i messaggi del kernel con un tempo in secondi dall'avvio, e permette di filtrarli per gravità, di convertire i tempi in date leggibili, di seguirli in diretta, di ottenerli in JSON e di svuotare il buffer. È in sola lettura per i messaggi: non li modifica, a meno che tu non chieda di cancellarli.

Come si usa

$ dmesg [opzioni]

Gli esempi dal "sandbox" sono output reali di una macchina virtuale di prova, con un kernel 6.18 e dmesg di util-linux 2.39; quelli di web01, il server degli articoli precedenti, sono illustrativi e servono a mostrare messaggi tipici. Righe lunghe sono state accorciate con cut, per entrare nella pagina.

Esempio 1: leggere i messaggi

$ dmesg | wc -l
374
$ dmesg | head -n 3 | cut -c1-70
[    0.000000] Linux version 6.18.44-fc-v236 (builder@sandboxing) (gcc (GCC)
[    0.000000] Command line: deferred_init=lazy dhash_entries=131072 ihash_en
[    0.000000] BIOS-provided physical RAM map:
$ dmesg | tail -n 3
$ dmesg | less

Ogni riga ha un numero tra parentesi quadre: sono i secondi trascorsi dall'avvio del kernel. Il tempo 0.000000 è l'inizio dell'avvio; più il numero è alto, più la riga è recente. Il buffer è lungo (qui 374 righe) ed è raro leggerlo tutto: si usa tail per gli ultimi messaggi, less per scorrerlo (vedi l'articolo su head e tail) o grep per cercare. Le prime righe (la versione del kernel e i parametri di avvio) si leggono anche con cat /proc/version e cat /proc/cmdline. Su alcune distribuzioni dmesg usa direttamente il pager quando l'output è lungo: si disattiva con -P.

Esempio 2: tempi leggibili

$ dmesg -T | tail -n 2
[Thu Nov  5 06:33:49 2026] prova articolo dmesg
[Thu Nov  5 06:33:51 2026] prova warn
$ dmesg -H | tail -n 2
[Nov 5 06:33] prova articolo dmesg
[  +1.998014] prova warn
$ dmesg --time-format=iso | tail -n 1
2026-11-05T06:33:51,285420+01:00 prova warn
$ dmesg -t | tail -n 1
prova warn

Dire "all'istante 2814,5" è poco utile: con -T (ctime) i secondi diventano una data e un'ora. Il kernel però conta i secondi dall'avvio e dmesg ricostruisce la data sottraendo il tempo trascorso dall'ora attuale: se il computer è stato sospeso (suspend), il risultato può essere sbagliato di qualche minuto o ora. Il manuale lo dice espressamente ("may be inaccurate"). Altre forme: -H (human) mostra un'ora generica e, per ogni riga, il tempo trascorso dalla precedente; --time-format=iso dà date in formato ISO, ordinabili e adatte agli script; -t toglie del tutto i tempi, per confrontare due output o passare il testo a un altro comando. Qui le righe finali sono due messaggi di prova che ho scritto io nel buffer (esempio 6).

Esempio 3: filtrare per gravità

$ dmesg -l err,warn -t
software IO TLB: No low mem
EXT4-fs (vda): warning: mounting unchecked fs, running e2fsck is recommended
$ dmesg -l warn+ -t | head -n 2 | cut -c1-60
software IO TLB: No low mem
EXT4-fs (vda): warning: mounting unchecked fs, running e2fsck is r
$ dmesg -x -t | sed -n 1,2p | cut -c1-60
kern  :notice: [    0.000000] Linux version 6.18.44-fc-v236 (builder@sandboxi
kern  :info  : [    0.000000] Command line: deferred_init=lazy dhash_entries=
$ dmesg -f kern,daemon -t | wc -l
374

I messaggi hanno un livello, dal più grave al meno grave: emerg (il sistema è inutilizzabile), alert, crit, err, warn, notice, info e debug. Con -l (level) si scelgono i livelli da mostrare: nell'esempio solo gli avvisi e gli errori (nel sandbox ce ne sono solo due, innocui). Il suffisso + include anche i livelli più gravi. Con -x (decode) ogni riga indica la facility (la provenienza: kern per il kernel, user per i programmi, daemon...) e il livello in forma leggibile. Con -f si filtra per facility. Per cercare problemi è il filtro più comodo: dmesg -l err,crit,alert,emerg.

Esempio 4: se non funziona senza sudo

$ dmesg
dmesg: read kernel buffer failed: Operation not permitted
$ sudo dmesg | tail -n 2
$ sysctl kernel.dmesg_restrict
kernel.dmesg_restrict = 1

Su molte distribuzioni un utente normale non può leggere il buffer, e riceve Operation not permitted (nel sandbox ho riprodotto l'errore con un utente senza privilegi). Il motivo è il parametro kernel.dmesg_restrict: a 1 solo l'amministratore legge il buffer, perché i messaggi del kernel possono rivelare indirizzi di memoria e dettagli utili a un attaccante (vedi l'articolo su sysctl). La soluzione normale è usare sudo dmesg. Si potrebbe mettere il parametro a 0, ma è una scelta di sicurezza: su un server è meglio lasciarlo com'è. Su altre distribuzioni (o con valore 0) l'utente normale può leggere.

Esempio 5: cercare un problema

$ sudo dmesg -T | grep -i -E 'error|fail|oom|killed|i/o' | tail -n 5
[Wed Nov  4 03:12:41 2026] Out of memory: Killed process 4821 (php-fpm)
[Wed Nov  4 03:12:41 2026] oom_reaper: reaped process 4821 (php-fpm)
[Thu Nov  5 01:07:19 2026] EXT4-fs error (device sdb1): ext4_find_entry:1455
[Thu Nov  5 01:07:19 2026] blk_update_request: I/O error, dev sdb, sector 2048
[Thu Nov  5 05:58:03 2026] r8169 0000:03:00.0 eno1: Link is Down
$ dmesg | grep -i vda
$ dmesg -t | grep -i -m 2 vda | cut -c1-80
virtio_blk virtio1: [vda] 536870912 512-byte logical blocks (275 GB/256 GiB)
virtio_blk virtio1: [vda] new size: 536870912 512-byte logical blocks (275 GB/256 GiB)

Le righe dell'OOM killer, degli errori di I/O e dell'interfaccia di rete (blocchi web01) sono illustrative, ma sono tra i messaggi più tipici. Out of memory: Killed process significa che la memoria è finita e il kernel ha eliminato un processo per salvare il sistema (vedi gli articoli su free e ps: è il motivo per cui un programma "muore da solo"). I/O error e EXT4-fs error sono segnali di un problema ai dischi o al file system (vedi lsblk e mount), da prendere sul serio. Link is Down riguarda un cavo o una scheda di rete (vedi ip). La seconda parte (con vda) è reale: mostra come cercare un dispositivo per nome; con -m 2 grep si ferma alla seconda riga trovata (vedi l'articolo su grep).

Esempio 6: seguire i messaggi in diretta

$ sudo dmesg -w
$ sudo dmesg -W -T
$ echo "prova articolo dmesg" | sudo tee /dev/kmsg
prova articolo dmesg
$ sudo dmesg -t | tail -n 1
prova articolo dmesg

Con -w (follow) dmesg resta in attesa e stampa i nuovi messaggi appena arrivano, come tail -f; si ferma con Ctrl+C. Con -W (follow-new) parte senza mostrare quelli già presenti. È utile per vedere "in diretta" cosa dice il kernel mentre si inserisce una chiavetta, si collega un cavo o si prova un servizio. Nel sandbox ho provato entrambe le opzioni. Si può anche scrivere un messaggio nel buffer, per i test o per segnare un momento: basta scrivere nel file speciale /dev/kmsg (con tee e sudo, perché la redirezione > la fa la shell senza privilegi: vedi gli articoli su tee e sysctl). Un messaggio scritto così compare con facility user. Con -u si vedono solo i messaggi dei programmi, con -k solo quelli del kernel.

Esempio 7: svuotare il buffer

$ sudo dmesg -C
$ sudo dmesg -c > /tmp/dmesg-prima.txt
$ sudo dmesg | wc -l
0

-C (clear) cancella il buffer; -c (read-clear) lo legge e poi lo cancella. Serve quando si vuole isolare un problema: si svuota, si ripete l'operazione che dà errore e si legge cosa è comparso. Ma attenzione: i messaggi cancellati sono persi (a meno che il sistema non li abbia già copiati in un file: vedi "Attenzione a"). Meglio salvarli prima, come nel secondo comando. Non ho eseguito queste due righe nel sandbox, per non perdere i dati di prova: l'effetto è quello descritto dal manuale.

Esempio 8: uso negli script

#!/bin/bash
# Segnala se il kernel ha registrato errori nel buffer dei messaggi
LIVELLI="emerg,alert,crit,err"
N=$(dmesg -t -l "$LIVELLI" 2>/dev/null | wc -l)
if [ "$N" -gt 0 ]; then
    echo "Il kernel ha registrato $N messaggi di errore:" >&2
    dmesg -t -l "$LIVELLI" | tail -n 5 >&2
    exit 1
fi
echo "Nessun errore nel buffer del kernel"

Lo script conta i messaggi dai livelli più gravi e, se ce ne sono, stampa gli ultimi cinque e termina con un errore (exit 1, per accorgersene da cron: vedi l'articolo su crontab). Si lancia con sudo (o dall'amministratore). L'ho provato nel sandbox: con il buffer pulito risponde "Nessun errore nel buffer del kernel"; dopo aver scritto un messaggio di livello err in /dev/kmsg, si è fermato con il codice 1 e con il messaggio. Con -J (JSON) dmesg produce anche un output strutturato, con livello, tempo e testo per ogni riga, da elaborare con jq.

Opzioni utili

  • dmesg: tutto il buffer; -T: date leggibili; -H: formato umano; --time-format=iso: date ISO; -t: senza tempi.
  • -l livelli: filtra per livello (err,warn, o warn+ per quel livello e i più gravi); -f facility: filtra per provenienza; -x: mostra facility e livello.
  • -w: segue i messaggi in diretta; -W: come -w, ma solo i nuovi.
  • -k: solo i messaggi del kernel; -u: solo quelli dei programmi.
  • --since, --until: intervallo di tempo (con una data o un tempo relativo come -1h).
  • -C: cancella il buffer; -c: legge e cancella; -J: JSON; -L: colori; -P: senza pager.
  • journalctl -k: gli stessi messaggi dal journal; journalctl -k -b -1: quelli dell'avvio precedente.

Attenzione a

  • Il buffer è circolare, e si perde al riavvio: su un sistema molto attivo, i messaggi vecchi vengono sovrascritti, e dopo un riavvio non ci sono più. Per l'avvio precedente serve il registro persistente: journalctl -k -b -1 (se il journal è salvato su disco: vedi l'articolo su journalctl), oppure il file /var/log/kern.log dove c'è rsyslog. Nel sandbox non c'era nessuno dei due.
  • Gli orari di -T non sono sicuri: dopo una sospensione, un'ibernazione o una correzione dell'ora di sistema possono essere sbagliati. Per gli orari esatti usa journalctl -k, che registra l'ora vera al momento del messaggio.
  • Non è necessariamente un problema, solo perché c'è scritto error o fail: nel buffer ci sono avvisi innocui (come i due del sandbox). Valuta il contesto e la frequenza: una riga isolata all'avvio non è lo stesso di una che si ripete ogni secondo.
  • Con sudo si può leggere, ma anche cancellare: dmesg -c e -C eliminano prove utili. Per un'indagine, salva sempre l'output prima: sudo dmesg -T > dmesg-$(date +%F).txt.
  • Un utente normale spesso non ha il permesso: vedi l'esempio 4; non rendere il buffer pubblico (kernel.dmesg_restrict=0) solo per comodità.
  • Nei container si vede il buffer della macchina ospite, se lo si può leggere; spesso è bloccato o vuoto. Il comando serve davvero sulla macchina fisica o virtuale, non dentro un container.
  • I messaggi dipendono dal kernel e dai driver: le righe d'esempio (OOM, I/O error, Link is Down) cambiano nella forma da una versione all'altra, e da un driver all'altro: cerca le parole chiave, non il testo esatto.

Riepilogo

ComandoCosa fa
sudo dmesgMostra i messaggi del kernel
sudo dmesg | tail -n 20Mostra gli ultimi messaggi
sudo dmesg -TCon data e ora leggibili
sudo dmesg -HFormato "umano", con i tempi relativi
sudo dmesg -l err,crit,alert,emergSolo errori gravi
sudo dmesg -xMostra provenienza e livello
sudo dmesg | grep -i usbCerca i messaggi di un dispositivo
sudo dmesg -wSegue i nuovi messaggi in diretta
sudo dmesg -T > file.txtSalva i messaggi in un file
sudo dmesg -cLegge e svuota il buffer
journalctl -k -b -1Messaggi del kernel dell'avvio precedente

Nel prossimo articolo: lsmod, per vedere i moduli caricati nel kernel, cioè i driver in uso.