将dmesg时间戳转换为自定义日期格式

时间:2012-12-15 08:55:52

标签: logging timestamp kernel

我正在尝试理解dmesg时间戳并发现很难将其转换为将其更改为java日期/自定义日期格式。

非常感谢任何帮助。

示例dmesg日志:

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

谢谢!

9 个答案:

答案 0 :(得分:151)

理解dmesg时间戳非常简单:它是自内核启动以来的几秒钟。因此,有了启动时间(uptime),您可以添加秒数并以您喜欢的任何格式显示它们。

或者更好的是,您可以使用-T选项并解析人类可读的格式。

来自man page

-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.

答案 1 :(得分:30)

dr回答的帮助下,我写了一个解决方法,将转换放入.bashrc中。如果您没有任何时间戳或已经有正确的时间戳,它不会破坏任何内容。

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

另外,关于dmesg时间戳转换逻辑的良好读数&amp;如何在没有时间戳时启用时间戳: https://supportcenter.checkpoint.com/supportcenter/portal?eventSubmit_doGoviewsolutiondetails=&solutionid=sk92677

答案 2 :(得分:13)

对于没有“dmesg -T”的系统,例如RHEL / CentOS 6,我喜欢前面lucas-cimon提供的“dmesg_with_human_timestamps”功能。虽然我们的一些盒子有很长的正常运行时间,但它有点麻烦。事实证明,dmesg中的内核时间戳是从各个CPU保持的正常运行时间值得出的。随着时间的推移,这与实时时钟不同步。因此,最近dmesg条目的最准确转换将基于CPU时钟而不是/ proc /正常运行时间。例如,在这里的特定CentOS 6.6框中:

# 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

考虑到CPU的正常运行时间以毫秒为单位,这里有近5个半小时的偏移量。所以我修改了脚本并在此过程中将其转换为原生bash:

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

答案 3 :(得分:11)

所以KevZero请求的解决方案较少,所以我想出了以下内容:

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'

以下是一个例子:

$ 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

如果您希望它执行得更好,请将proc的时间戳改为变量:)

答案 4 :(得分:4)

在dmesg的最新版本中,您只需拨打dmesg -T

答案 5 :(得分:3)

您需要在/ proc / stat中引用“btime”,这是系统最新启动时的Unix纪元时间。然后,您可以基于该系统启动时间,然后添加dmesg中给出的经过的秒数来计算每个事件的时间戳。

答案 6 :(得分:3)

对于较旧的Linux发行版,另一种选择是使用包装脚本,例如在Perl或Python中。

请参阅此处的解决方案:

http://linuxaria.com/article/how-to-make-dmesg-timestamp-human-readable?lang=en http://jmorano.moretrix.com/2012/03/dmesg-human-readable-timestamps/

答案 7 :(得分:2)

如果您没有dmesg的{​​{1}}选项,例如Andoid,则可以使用busybox版本。以下解决了其他一些问题:

  1. [0.0000]格式之前的内容看起来像错位的颜色信息,前缀如<6>
  2. 从花车中制作整数。
  3. 灵感来自this blog post

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

    但请注意,此实现速度很慢。

答案 8 :(得分:0)

其他答案似乎没有提及的警告是,dmesg 显示的时间没有考虑任何睡眠/暂停时间。因此,在某些情况下,使用dmesg -T的通常答案不起作用,并且显示出完全错误的时间。

这种情况的一种解决方法是在某个已知时间将某些内容写入内核日志,然后将该条目用作计算其他时间的参考。显然,它只会在上次暂停后的一段时间内起作用。

因此,要显示自上次引导以来可能已暂停的计算机上最近输入的正确时间,请使用我的other answer here中的类似信息:

# write current time to kernel ring buffer so it appears in dmesg output
echo "timecheck: $(date +%s) = $(date +%F_%T)" | sudo tee /dev/kmsg

# use our "timecheck" entry to get the difference
# between the dmesg timestamp and real time
offset=$(dmesg | grep timecheck | tail -1 \
| perl -nle '($t1,$t2)=/^.(\d+)\S+ timecheck: (\d+)/; print $t2-$t1')

# pipe dmesg output through a Perl snippet to
# convert it's timestamp to correct readable times
dmesg | tail \
| perl -pe 'BEGIN{$offset=shift} s/^\[(\d+)\S+/localtime($1+$offset)/e' $offset