Converti timestamp dmesg in formato data personalizzato


112

Sto cercando di capire il timestamp dmesg e trovo difficile convertirlo per cambiarlo in formato data java / data personalizzato.

Ogni aiuto è molto apprezzato.

Registro dmesg di esempio:

[14614.647880] airo(eth1): link lost (missed beacons)

Grazie!

Risposte:


180

Capire il dmesgtimestamp è piuttosto semplice: è il tempo in secondi da quando il kernel è stato avviato. Quindi, avendo il tempo di avvio ( uptime), puoi sommare i secondi e mostrarli nel formato che preferisci.

O meglio, potresti usare l' -Topzione della riga di comando dmesge analizzare il formato leggibile dall'uomo.

Dalla pagina man :

-T, --ctime
    Print human readable timestamps. The timestamp could be inaccurate!

    The time source used for the logs is not updated after system SUSPEND/RESUME.

10
Quale comando accetta -T? Il mio dmesg non lo dice, né la manpage lo dice. (Linux Mint Debian Edition).
Gyorgyabraham

1
Il mio fa ( dmesgda util-linux 2.20.1Ubuntu 13.04)

2
Non disponibile in redhat e / o oracle linux 5.6, rpm -qf /bin/dmesg => util-linux-2.13-0.56.0.2.el5
michael

7
Questa opzione è apparsa in util-linux 2.20, secondo le note di rilascio: ftp.kernel.org/pub/linux/utils/util-linux/v2.20/…
ks1322

1
@xealits, grazie per il follow-up, è gentile da parte tua :) Per quanto riguarda la domanda, penso che la parte di comprensione sia minore e il "convertilo per cambiarlo in formato data java / data personalizzato". era la parte fondamentale, ma la tua opinione potrebbe essere diversa. Buona giornata;)

32

Con l'aiuto di dr answer, ho scritto una soluzione alternativa che rende la conversione da inserire nel tuo .bashrc. Non interromperà nulla se non hai alcun timestamp o timestamp già corretti.

dmesg_with_human_timestamps () {
    $(type -P dmesg) "$@" | perl -w -e 'use strict;
        my ($uptime) = do { local @ARGV="/proc/uptime";<>}; ($uptime) = ($uptime =~ /^(\d+)\./);
        foreach my $line (<>) {
            printf( ($line=~/^\[\s*(\d+)\.\d+\](.+)/) ? ( "[%s]%s\n", scalar localtime(time - $uptime + $1), $2 ) : $line )
        }'
}
alias dmesg=dmesg_with_human_timestamps

Inoltre, una buona lettura sulla logica di conversione del timestamp dmesg e su come abilitare i timestamp quando non ce ne sono: https://supportcenter.checkpoint.com/supportcenter/portal?eventSubmit_doGoviewsolutiondetails=&solutionid=sk92677


miglioramento minore: puoi rimuovere 'tail -1' nella pipeline e lasciare che awk mangi le righe e stampi dalla riga finale nel suo buffer. local dmesg_bin=$(type -a dmesg | awk 'END { print $NF }')
Brian Onn

@ Lucas: puoi spiegare usando 'type -a dmesg | ...' invece di $ (which dmesg)? C'è un vantaggio in un tubo a 3 stadi per ottenere quel percorso?
Stabledog

@ Stabledog: bella domanda. Per una spiegazione sul perché utilizzare typeover which, vedere questa domanda . Ho modificato la mia risposta per evitare l'inutile triplo tubo.
Lucas Cimon

questo frammento di bash / perl ha funzionato per me, ho una vecchia macchina RHEL5.7 di cui devo occuparmi e dmesg non ha alcuna opzione per stampare il timestamp in tempo umano.
Paul M

17

Per i sistemi senza "dmesg -T" come RHEL / CentOS 6, mi è piaciuta la funzione "dmesg_with_human_timestamps" fornita da lucas-cimon in precedenza. Tuttavia, ha un po 'di problemi con alcune delle nostre scatole con tempi di attività elevati. Risulta che i timestamp del kernel in dmesg derivano da un valore di uptime mantenuto dalle singole CPU. Nel tempo questo perde la sincronizzazione con l'orologio in tempo reale. Di conseguenza, la conversione più accurata per le voci dmesg recenti sarà basata sull'orologio della CPU anziché su / proc / uptime. Ad esempio, su una particolare scatola CentOS 6.6 qui:

# grep "\.clock" /proc/sched_debug  | head -1
  .clock                         : 32103895072.444568
# uptime
 15:54:05 up 371 days, 19:09,  4 users,  load average: 3.41, 3.62, 3.57
# cat /proc/uptime
32123362.57 638648955.00

Considerando il tempo di attività della CPU in millisecondi, qui c'è un offset di quasi 5 ore e mezza. Quindi ho rivisto lo script e l'ho convertito in bash nativo nel processo:

dmesg_with_human_timestamps () {
    FORMAT="%a %b %d %H:%M:%S %Y"

    now=$(date +%s)
    cputime_line=$(grep -m1 "\.clock" /proc/sched_debug)

    if [[ $cputime_line =~ [^0-9]*([0-9]*).* ]]; then
        cputime=$((BASH_REMATCH[1] / 1000))
    fi

    dmesg | while IFS= read -r line; do
        if [[ $line =~ ^\[\ *([0-9]+)\.[0-9]+\]\ (.*) ]]; then
            stamp=$((now-cputime+BASH_REMATCH[1]))
            echo "[$(date +"${FORMAT}" --date=@${stamp})] ${BASH_REMATCH[2]}"
        else
            echo "$line"
        fi
    done
}

alias dmesgt=dmesg_with_human_timestamps

La funzione non ha funzionato in zsh. Ho dovuto farlo in modo corretto. Detto questo, su una scatola con 221 giorni di operatività, questa soluzione aveva il timestamp fino al minuto effettivo. Altre soluzioni hanno mostrato che l'evento della causa principale si verificava più di 2 ore prima nel corso della giornata. Grazie, Allen. Mi hai salvato il pomeriggio.
Trenton,

Le macchine RHEL5.x non sembrano avere / proc / sched_debug :-(
Paul M

14

Quindi KevZero ha richiesto una soluzione meno complicata, quindi ho pensato a quanto segue:

sed -r 's#^\[([0-9]+\.[0-9]+)\](.*)#echo -n "[";echo -n $(date --date="@$(echo "$(grep btime /proc/stat|cut -d " " -f 2)+\1" | bc)" +"%c");echo -n "]";echo -n "\2"#e'

Ecco un esempio:

$ dmesg|tail | sed -r 's#^\[([0-9]+\.[0-9]+)\](.*)#echo -n "[";echo -n $(date --date="@$(echo "$(grep btime /proc/stat|cut -d " " -f 2)+\1" | bc)" +"%c");echo -n "]";echo -n "\2"#e'
[2015-12-09T04:29:20 COT] cfg80211:   (57240000 KHz - 63720000 KHz @ 2160000 KHz), (N/A, 0 mBm), (N/A)
[2015-12-09T04:29:23 COT] wlp3s0: authenticate with dc:9f:db:92:d3:07
[2015-12-09T04:29:23 COT] wlp3s0: send auth to dc:9f:db:92:d3:07 (try 1/3)
[2015-12-09T04:29:23 COT] wlp3s0: authenticated
[2015-12-09T04:29:23 COT] wlp3s0: associate with dc:9f:db:92:d3:07 (try 1/3)
[2015-12-09T04:29:23 COT] wlp3s0: RX AssocResp from dc:9f:db:92:d3:07 (capab=0x431 status=0 aid=6)
[2015-12-09T04:29:23 COT] wlp3s0: associated
[2015-12-09T04:29:56 COT] thinkpad_acpi: EC reports that Thermal Table has changed
[2015-12-09T04:29:59 COT] i915 0000:00:02.0: BAR 6: [??? 0x00000000 flags 0x2] has bogus alignment
[2015-12-09T05:00:52 COT] thinkpad_acpi: EC reports that Thermal Table has changed

Se vuoi che funzioni un po 'meglio, metti invece il timestamp da proc in una variabile :)


4

Nelle versioni recenti di dmesg, puoi semplicemente chiamare dmesg -T.


3
La stessa risposta era già stata data da RC due anni prima della tua.
Josch

4

Se non hai l' -Topzione per dmesgcome ad esempio su Andoid, puoi utilizzare la busyboxversione. Quanto segue risolve anche alcuni altri problemi:

  1. Il [0.0000]formato è preceduto da qualcosa che assomiglia a informazioni di colore fuori posto, come prefissi <6>.
  2. Crea numeri interi da float.

È ispirato a questo post del blog .

#!/bin/sh                                                                                                               
# Translate dmesg timestamps to human readable format                                                                   

# uptime in seconds                                                                                                     
uptime=$(cut -d " " -f 1 /proc/uptime)                                                                                  

# remove fraction                                                                                                       
uptime=$(echo $uptime | cut -d "." -f1)                                                                                 

# run only if timestamps are enabled                                                                                    
if [ "Y" = "$(cat /sys/module/printk/parameters/time)" ]; then                                                          
  dmesg | sed "s/[^\[]*\[/\[/" | sed "s/^\[[ ]*\?\([0-9.]*\)\] \(.*\)/\\1 \\2/" | while read timestamp message; do      
    timestamp=$(echo $timestamp | cut -d "." -f1)                                                                       
    ts1=$(( $(busybox date +%s) - $uptime + $timestamp ))                                                               
    ts2=$(busybox date -d "@${ts1}")                                                                                    
    printf "[%s] %s\n" "$ts2" "$message"                                                                                
  done                                                                                                                  
else                                                                                                                    
  echo "Timestamps are disabled (/sys/module/printk/parameters/time)"                                                   
fi                                                                                                                      

Notare, tuttavia, che questa implementazione è piuttosto lenta.


3

sarà necessario fare riferimento a "btime" in / proc / stat, che è l'ora di Unix in cui il sistema è stato avviato per l'ultima volta. Quindi puoi basarti su quel tempo di avvio del sistema e quindi aggiungere i secondi trascorsi forniti in dmesg per calcolare il timestamp per ogni evento.


Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.