How do I convert dmesg timestamp to custom date format?

前端 未结 9 1218
感动是毒
感动是毒 2020-12-12 17:41

I am trying to understand the dmesg timestamp and find it hard to convert that to change it to java date/custom date format.

Sample dmesg log:

<         


        
相关标签:
9条回答
  • 2020-12-12 18:17

    you will need to reference the "btime" in /proc/stat, which is the Unix epoch time when the system was latest booted. Then you could base on that system boot time and then add on the elapsed seconds given in dmesg to calculate timestamp for each events.

    0 讨论(0)
  • 2020-12-12 18:17

    A caveat which the other answers don't seem to mention is that the time which is shown by dmesg doesn't take into account any sleep/suspend time. So there are cases where the usual answer of using dmesg -T doesn't work, and shows a completely wrong time.

    A workaround for such situations is to write something to the kernel log at a known time and then use that entry as a reference to calculate the other times. Obviously, it will only work for times after the last suspend.

    So to display the correct time for recent entries on machines which may have been suspended since their last boot, use something like this from my 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
    
    0 讨论(0)
  • 2020-12-12 18:26

    Understanding dmesg timestamp is pretty simple: it is time in seconds since the kernel started. So, having time of startup (uptime), you can add up the seconds and show them in whatever format you like.

    Or better, you could use the -T command line option of dmesg and parse the human readable format.

    From the 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.
    
    0 讨论(0)
  • 2020-12-12 18:26

    For systems without "dmesg -T" such as RHEL/CentOS 6, I liked the "dmesg_with_human_timestamps" function provided by lucas-cimon earlier. It has a bit of trouble with some of our boxes with large uptime though. Turns out that kernel timestamps in dmesg are derived from an uptime value kept by individual CPUs. Over time this gets out of sync with the real time clock. As a result, the most accurate conversion for recent dmesg entries will be based on the CPU clock rather than /proc/uptime. For example, on a particular CentOS 6.6 box here:

    # 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
    

    Accounting for the CPU uptime being in milliseconds, there's an offset of nearly 5 1/2 hours here. So I revised the script and converted it to native bash in the process:

    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
    
    0 讨论(0)
  • 2020-12-12 18:26

    With older Linux distros yet another option is to use wrapping script, e.g. in Perl or Python.

    See solutions here:

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

    0 讨论(0)
  • 2020-12-12 18:27

    With the help of dr answer, I wrote a workaround that makes the conversion to put in your .bashrc. It won't break anything if you don't have any timestamp or already correct timestamps.

    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
    

    Also, a good reading on the dmesg timestamp conversion logic & how to enable timestamps when there are none: https://supportcenter.checkpoint.com/supportcenter/portal?eventSubmit_doGoviewsolutiondetails=&solutionid=sk92677

    0 讨论(0)
提交回复
热议问题