Konwertuj znacznik czasu dmesg na niestandardowy format daty

112

Próbuję zrozumieć znacznik czasu dmesg i trudno jest go przekonwertować, aby zmienić go na datę java / niestandardowy format daty.

każda pomoc jest bardzo ceniona.

Przykładowy dziennik dmesg:

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

Dzięki!

ukanth
źródło

Odpowiedzi:

180

Zrozumienie dmesgznacznika czasu jest dość proste: jest to czas w sekundach od uruchomienia jądra. Więc mając czas na uruchomienie (uptime ), możesz dodać sekundy i pokazać je w dowolnym formacie.

Albo lepiej, możesz użyć -Topcji wiersza poleceń dmesgi przeanalizować format czytelny dla człowieka.

Od strony 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.
drescherjm
źródło
10
Jakie polecenie akceptuje -T? Mój dmesg tego nie robi, żadna z podręczników tego nie mówi. (Linux Mint Debian Edition).
gyorgyabraham
1
Mój robi ( dmesgspod util-linux 2.20.1Ubuntu 13.04)
2
Niedostępne w redhat i / lub oracle linux 5.6, rpm -qf /bin/dmesg => util-linux-2.13-0.56.0.2.el5
michael
7
Ta opcja pojawiła się util-linux 2.20, zgodnie z Uwagami
ks1322
1
@xealits dzięki za kontynuację, to miło z twojej strony :) Jeśli chodzi o pytanie, myślę, że część zrozumienia jest niewielka i „przekonwertuj to, aby zmienić to na datę java / niestandardowy format daty”. była najważniejsza, ale Twoja opinia może się różnić. Miłego dnia;)
32

Z pomocą odpowiedzi dr , napisałem obejście, które sprawia, że ​​konwersja jest umieszczana w twoim .bashrc. Nic nie zepsuje, jeśli nie masz żadnego znacznika czasu lub masz już poprawne sygnatury czasowe.

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

Warto też przeczytać o logice konwersji znaczników czasu dmesg i o tym, jak włączyć znaczniki czasu, gdy ich nie ma: https://supportcenter.checkpoint.com/supportcenter/portal?eventSubmit_doGoviewsolutiondetails=&solutionid=sk92677

Lucas Cimon
źródło
niewielkie ulepszenie: możesz usunąć 'tail -1' w potoku i po prostu pozwolić awk zjadać linie i wypisać z ostatniej linii w swoim buforze. local dmesg_bin=$(type -a dmesg | awk 'END { print $NF }')
Brian Onn
@Lucas: czy możesz wyjaśnić użycie 'type -a dmesg | ...' zamiast $ (który dmesg)? Czy trójstopniowa rura ma jakąś zaletę w uzyskaniu takiej ścieżki?
Stabledog
@Stabledog: dobre pytanie. Aby uzyskać wyjaśnienie, dlaczego używasz typeover which, zobacz to pytanie . Jednak zredagowałem odpowiedź, aby uniknąć bezużytecznej potrójnej rurki.
Lucas Cimon
ten fragment bash / perl zadziałał dla mnie, mam starą maszynę RHEL5.7, którą muszę się opiekować, a dmesg nie ma opcji drukowania znacznika czasu w czasie ludzkim.
Paul M
17

W przypadku systemów bez "dmesg -T", takich jak RHEL / CentOS 6, podobała mi się funkcja "dmesg_with_human_timestamps" dostarczona wcześniej przez lucas-cimon . Ma jednak trochę problemów z niektórymi z naszych pudełek z dużym czasem sprawności. Okazuje się, że sygnatury czasowe jądra w dmesg pochodzą z wartości czasu pracy utrzymywanej przez poszczególne procesory. Z czasem traci to synchronizację z zegarem czasu rzeczywistego. W rezultacie najdokładniejsza konwersja dla ostatnich wpisów dmesg będzie oparta na zegarze procesora, a nie na / proc / uptime. Na przykład w konkretnym pudełku CentOS 6.6 tutaj:

# 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

Uwzględniając czas pracy procesora w milisekundach, jest tutaj przesunięcie o prawie 5 1/2 godziny. Więc poprawiłem skrypt i przekonwertowałem go na natywny bash w procesie:

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
źródło
Funkcja nie działała w zsh. Musiałem to zrobić w odpowiednim bashu. To powiedziawszy, na pudełku z 221 dniami pracy, to rozwiązanie miało znacznik czasu z dokładnością do minuty. Inne rozwiązania pokazały, że zdarzenie źródłowe miało miejsce ponad 2 godziny wcześniej w ciągu dnia. Dzięki, Allen. Uratowałeś mi popołudnie.
Trenton
Wydaje się, że komputery RHEL5.x nie mają / proc / schedule_debug :-(
Paul M
14

Więc KevZero zażądał mniej niezdarnego rozwiązania, więc wymyśliłem:

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'

Oto przykład:

$ 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

Jeśli chcesz, aby działało trochę lepiej, zamiast tego umieść znacznik czasu z proc w zmiennej :)

runejuhl
źródło
4

W najnowszych wersjach dmesg możesz po prostu zadzwonić dmesg -T.

Steffen Heil
źródło
3
Ta sama odpowiedź została udzielona przez RC już dwa lata przed twoją.
josch
4

Jeśli nie masz -Topcji dmesgjak na przykład na Andoidzie, możesz skorzystać z busyboxwersji. Poniższe rozwiązania rozwiązują również inne problemy:

  1. [0.0000]Format jest poprzedzone czymś, co wygląda jak niesłuszna informacji o kolorze, prefiksy podoba <6>.
  2. Twórz liczby całkowite z liczb zmiennoprzecinkowych.

Inspiruje się tym postem na blogu .

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

Należy jednak pamiętać, że ta implementacja jest dość powolna.

Anne van Rossum
źródło
3

będziesz musiał odwołać się do "btime" w / proc / stat, który jest czasem uniksowym, kiedy system był ostatnio uruchamiany. Następnie możesz oprzeć się na tym czasie rozruchu systemu, a następnie dodać upływające sekundy podane w dmesg, aby obliczyć znacznik czasu dla każdego zdarzenia.

imcom
źródło