Konvertieren Sie den dmesg-Zeitstempel in ein benutzerdefiniertes Datumsformat

111

Ich versuche, den dmesg-Zeitstempel zu verstehen und finde es schwierig, ihn zu konvertieren, um ihn in das Java-Datums- / benutzerdefinierte Datumsformat zu ändern.

Jede Hilfe wird sehr geschätzt.

Beispiel dmesg log:

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

Vielen Dank!

Ukanth
quelle

Antworten:

179

Das Verständnis des dmesgZeitstempels ist ziemlich einfach: Es ist Zeit in Sekunden, seit der Kernel gestartet wurde. Also, Zeit für den Start haben (uptime ) haben, können Sie die Sekunden addieren und in einem beliebigen Format anzeigen.

Oder besser, Sie können die -TBefehlszeilenoption verwenden dmesgund das lesbare Format analysieren.

Von der Manpage :

-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.
drescherjm
quelle
10
Welcher Befehl akzeptiert -T? Mein dmesg nicht, keine Manpage sagt es. (Linux Mint Debian Edition).
Gyorgyabraham
1
Mine hat ( dmesgvon util-linux 2.20.1unter Ubuntu 13.04)
2
Nicht verfügbar in Redhat und / oder Oracle Linux 5.6, rpm -qf /bin/dmesg => util-linux-2.13-0.56.0.2.el5
Michael
7
Diese Option util-linux 2.20wurde laut Versionshinweisen
angezeigt
1
@xealits danke für das Follow-up, das ist nett von dir :) In Bezug auf die Frage denke ich, dass der verständnisvolle Teil geringfügig ist und das "Konvertieren, um es in Java-Datum / benutzerdefiniertes Datumsformat zu ändern". war der Kernteil, aber Ihre Meinung könnte abweichen. Habt einen schönen Tag;)
32

Mit Hilfe von Dr. Answer habe ich eine Problemumgehung geschrieben, die die Konvertierung in Ihre .bashrc-Datei ermöglicht. Es wird nichts kaputt machen, wenn Sie keinen Zeitstempel oder bereits korrekte Zeitstempel haben.

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

Außerdem eine gute Lektüre zur Konvertierungslogik für dmesg-Zeitstempel und zum Aktivieren von Zeitstempeln, wenn keine vorhanden sind: https://supportcenter.checkpoint.com/supportcenter/portal?eventSubmit_doGoviewsolutiondetails=&solutionid=sk92677

Lucas Cimon
quelle
geringfügige Verbesserung: Sie können 'tail -1' in der Pipeline entfernen und awk einfach Zeilen essen lassen und von der letzten Zeile in ihrem Puffer drucken lassen. local dmesg_bin=$(type -a dmesg | awk 'END { print $NF }')
Brian Onn
@Lucas: Kannst du erklären, wie 'type -a dmesg | ...' anstelle von $ (welches dmesg) verwendet wird? Gibt es einen Vorteil für ein dreistufiges Rohr, um diesen Weg zu finden?
Stabledog
@Stabledog: gute Frage. Eine Erklärung zur Verwendung von typeover whichfinden Sie in dieser Frage . Ich habe meine Antwort bearbeitet, um die nutzlose Triple Pipe zu vermeiden.
Lucas Cimon
Dieses Bash / Perl-Snippet hat bei mir funktioniert. Ich habe eine alte RHEL5.7-Maschine, um die ich mich kümmern muss, und dmesg hat keine Möglichkeit, einen Zeitstempel in menschlicher Zeit zu drucken.
Paul M
17

Für Systeme ohne "dmesg -T" wie RHEL / CentOS 6 mochte ich die Funktion "dmesg_with_human_timestamps", die früher von lucas-cimon bereitgestellt wurde . Es gibt jedoch einige Probleme mit einigen unserer Boxen mit großer Betriebszeit. Es stellt sich heraus, dass Kernel-Zeitstempel in dmesg von einem Verfügbarkeitswert abgeleitet werden, der von einzelnen CPUs gehalten wird. Mit der Zeit wird dies nicht mehr mit der Echtzeituhr synchronisiert. Infolgedessen basiert die genaueste Konvertierung für die letzten dmesg-Einträge eher auf der CPU-Uhr als auf / proc / uptime. Zum Beispiel auf einer bestimmten CentOS 6.6-Box hier:

# 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

Berücksichtigt man die CPU-Verfügbarkeit in Millisekunden, ergibt sich hier ein Offset von fast 5 1/2 Stunden. Also habe ich das Skript überarbeitet und es dabei in native Bash konvertiert:

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
Allen Belletti
quelle
Funktion hat in zsh nicht funktioniert. Musste es in Bash richtig machen. Auf einer Box mit 221 Tagen Betriebszeit hatte diese Lösung den Zeitstempel auf die Minute der tatsächlichen Zeit reduziert. Andere Lösungen zeigten, dass das Grundereignis 2+ Stunden früher am Tag auftrat. Danke, Allen. Du hast meinen Nachmittag gerettet.
Trenton
RHEL5.x-Maschinen scheinen / proc / sched_debug nicht zu haben :-(
Paul M
14

Also bat KevZero um eine weniger klobige Lösung, und so kam ich auf Folgendes:

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'

Hier ist ein Beispiel:

$ 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

Wenn Sie möchten, dass es etwas besser funktioniert, setzen Sie stattdessen den Zeitstempel von proc in eine Variable :)

Runejuhl
quelle
4

In neueren Versionen von dmesg können Sie einfach aufrufen dmesg -T.

Steffen Heil
quelle
3
Die gleiche Antwort gab RC bereits zwei Jahre vor Ihrer.
Josch
4

Wenn Sie nicht die -TOption haben, dmesgwie zum Beispiel für Andoid, können Sie die busyboxVersion verwenden. Das Folgende löst auch einige andere Probleme:

  1. Dem [0.0000]Format geht etwas voraus, das wie falsch platzierte Farbinformationen aussieht, wie Präfixe wie<6> .
  2. Machen Sie ganze Zahlen aus Floats.

Es ist inspiriert von diesem Blog-Beitrag .

#!/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                                                                                                                      

Beachten Sie jedoch, dass diese Implementierung ziemlich langsam ist.

Anne van Rossum
quelle
3

Sie müssen auf die "btime" in / proc / stat verweisen. Dies ist die Unix-Epoche, in der das System zuletzt gestartet wurde. Dann können Sie sich auf diese Systemstartzeit stützen und dann die in dmesg angegebenen verstrichenen Sekunden addieren, um den Zeitstempel für jedes Ereignis zu berechnen.

imcom
quelle