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

Posted

技术标签:

【中文标题】如何将 dmesg 时间戳转换为自定义日期格式?【英文标题】:How do I convert dmesg timestamp to custom date format? 【发布时间】:2012-12-03 04:03:52 【问题描述】:

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

dmesg 日志示例:

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

那么如何将14614.647880 转换为标准日期?

【问题讨论】:

【参考方案1】:

了解dmesg 时间戳非常简单:它是自内核启动以来的时间,以秒为单位。因此,如果有启动时间 (uptime),您可以将秒数相加并以您喜欢的任何格式显示。

或者更好的是,您可以使用dmesg-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.

【讨论】:

什么命令接受 -T ?我的 dmesg 没有,联机帮助页也没有告诉它。 (Linux Mint Debian 版)。 我的可以(dmesg from util-linux 2.20.1 under Ubuntu 13.04) 在 redhat 和/或 oracle linux 5.6 中不可用,rpm -qf /bin/dmesg => util-linux-2.13-0.56.0.2.el5 这个选项出现在util-linux 2.20,根据发行说明:ftp.kernel.org/pub/linux/utils/util-linux/v2.20/… @xealits 感谢您的跟进,你真好 :) 关于这个问题,我认为理解部分是次要的,并且“将其转换为 java 日期/自定义日期格式”。是核心部分,但您的意见可能会有所不同。祝你有美好的一天;)【参考方案2】:

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

【讨论】:

【参考方案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/

【讨论】:

【参考方案4】:

在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 时间戳转换逻辑以及如何在没有时间戳时启用时间戳的好读物: https://supportcenter.checkpoint.com/supportcenter/portal?eventSubmit_doGoviewsolutiondetails=&solutionid=sk92677

【讨论】:

小改进:您可以删除管道中的“tail -1”,让 awk 吃线并从缓冲区的最后一行打印。 local dmesg_bin=$(type -a dmesg | awk 'END print $NF ') @Lucas:你能解释一下使用 'type -a dmesg|...' 而不是 $(which dmesg) 吗? 3 级管道获得该路径是否有优势? @Stabledog:好问题。有关为什么使用type 而不是which 的解释,请参阅this question。我编辑了我的答案以避免无用的三重管道。 这个 bash/perl sn-p 为我工作,我有一台旧的 RHEL5.7 机器我必须照看,而 dmesg 无法在人工时间打印时间戳。【参考方案5】:

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

【讨论】:

RC 在你之前两年已经给出了同样的答案。【参考方案6】:

如果您没有 dmesg-T 选项,例如在 Andoid 上,您可以使用 busybox 版本。以下还解决了其他一些问题:

    [0.0000] 格式前面有一些看起来像错位的颜色信息,前缀如 &lt;6&gt;。 从浮点数中生成整数。

灵感来自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                                                                                                                      

但是请注意,这个实现非常慢。

【讨论】:

【参考方案7】:

所以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 中的时间戳放入变量中:)

【讨论】:

【参考方案8】:

对于RHEL/CentOS 6等没有“dmesg -T”的系统,我喜欢之前lucas-cimon提供的“dmesg_with_human_timestamps”功能。不过,我们的一些正常运行时间较长的盒子有点麻烦。事实证明,dmesg 中的内核时间戳是从单个 CPU 保存的正常运行时间值得出的。随着时间的推移,这与实时时钟不同步。因此,最近 dmesg 条目的最准确转换将基于 CPU 时钟而不是 /proc/uptime。例如,在此处的特定 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 1/2 小时。于是我修改了脚本,并在过程中将其转换为原生 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

【讨论】:

该功能在 zsh 中不起作用。必须在 bash 中正确执行。也就是说,在一个正常运行时间为 221 天​​的机器上,这个解决方案的时间戳可以精确到实际的分钟。其他解决方案显示,根本原因事件发生在当天早些时候 2 个多小时。谢谢,艾伦。你拯救了我的下午。 RHEL5.x 机器似乎没有 /proc/sched_debug :-(【参考方案9】:

其他答案似乎没有提到的一个警告是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

【讨论】:

【参考方案10】:

dmesg -T 可能会显示错误的时间,与date 命令输出不同。

解决方法是带 -k、--dmesg 的 journalctl。我使用 -k 因为它更短:

journalctl -k

它将只显示内核消息和正确的时间。

仅显示匹配短语的内核行:

journalctl -kg phrase

【讨论】:

以上是关于如何将 dmesg 时间戳转换为自定义日期格式?的主要内容,如果未能解决你的问题,请参考以下文章

如何将时间字符串转换为自定义日期格式?

如何实现时间戳转换

js页面里时间戳转日期

使用JS,时间戳数值怎么转换成日期

js时间戳怎么转成日期格式

js怎么把时间戳转换为日期格式