Nov 132011
 

After the update to Ubuntu 11.10 my wireless goes up and down, and so i’m trying to debug this problem looking into dmesg.

But this brought me to another small issue, dmesg prints timestamps in the form of seconds.nanoseconds since the system booted. And no, there seems to be no -h option to make it human readable. so you should check your boot time and make some calculations to see where the events logged are happened.

This don’t seem so useful !
Let’s see how to have these information in a better format.



First a really short introduction to dmesg, from the man page:

dmesg is used to examine or control the kernel ring buffer.

In short, giving the command dmesg from a terminal you can see the boot message or any message regarding the kernel while your system is running. And now back on the logs.

Debian and Ubuntu

While I was looking around for a solution i’ve discovered that for these distributions there is an easy way to solve the problem, instead of using the command dmesg just check the file /var/log/kern.log

There you’ll see entry like mine, with the date nicely formatted:

Nov 13 18:37:19 xubuntu-home kernel: [14850.508867] airo(eth1): link lost (missed beacons)
Nov 13 18:38:29 xubuntu-home kernel: [14920.467041] airo(eth1): link lost (missed beacons)
Nov 13 18:38:44 xubuntu-home kernel: [14935.605833] ADDRCONF(NETDEV_UP): eth0: link is not ready
Nov 13 18:38:53 xubuntu-home kernel: [14943.868439] ADDRCONF(NETDEV_UP): eth0: link is not ready
Nov 13 18:39:03 xubuntu-home kernel: [14954.592045] eth1: no IPv6 routers present
Nov 13 18:39:08 xubuntu-home kernel: [14958.742806] type=1400 audit(1321205948.113:29): apparmor="DENIED" operation="open" parent=13015 profile="/sbin/dhclient" name="/var/lib/wicd/dhclient.conf" pid=13067 comm="dhclient" requested_mask="r" denied_mask="r" fsuid=0 ouid=0
Nov 13 19:22:46 xubuntu-home kernel: [17577.082369] airo(eth1): link lost (missed beacons)

So, problem solved on these distributions.

Fedora, CentOS and all the others

Ok, so your distribution don’t use /var/log/kern.log and so your dmesg show lines like these:

[14614.647880] airo(eth1): link lost (missed beacons)
[14850.508867] airo(eth1): link lost (missed beacons)
[14920.467041] airo(eth1): link lost (missed beacons)
[14935.605833] ADDRCONF(NETDEV_UP): eth0: link is not ready
[14943.868439] ADDRCONF(NETDEV_UP): eth0: link is not ready
[14954.592045] eth1: no IPv6 routers present
[14958.742806] type=1400 audit(1321205948.113:29): apparmor="DENIED" operation="open" parent=13015 profile="/sbin/dhclient" name="/var/lib/wicd/dhclient.conf" pid=13067 comm="dhclient" requested_mask="r" denied_mask="r" fsuid=0 ouid=0
[17577.082369] airo(eth1): link lost (missed beacons)

I’ve found 2 solutions to parse the dmesg output and have it human readable one in Perl and one in Python.

This is the solution in perl:

#!/usr/bin/perl
 
use strict;
use warnings;
 
my @dmesg_new = ();
my $dmesg = "/bin/dmesg";
my @dmesg_old = `$dmesg`;
my $now = time();
my $uptime = `cat /proc/uptime | cut -d"." -f1`;
my $t_now = $now - $uptime;
 
sub format_time {
 my @time = localtime $_[0];
 $time[4]+=1;    # Adjust Month
 $time[5]+=1900;    # Adjust Year
 return sprintf '%4i-%02i-%02i %02i:%02i:%02i', @time[reverse 0..5];
}
 
foreach my $line ( @dmesg_old )
{
 chomp( $line );
 if( $line =~ m/\[\s*(\d+)\.(\d+)\](.*)/i )
 {
 # now - uptime + sekunden
 my $t_time = format_time( $t_now + $1 );
 push( @dmesg_new , "[$t_time] $3" );
 }
}
 
print join( "\n", @dmesg_new );
print "\n";

Just copy and paste these lines in a file, make it executable and run it, you’ll have the dmesg output but with an human readable time format:

[2011-11-13 16:57:10]  airo(eth1): link lost (missed beacons)
[2011-11-13 16:57:34]  ADDRCONF(NETDEV_UP): eth0: link is not ready
[2011-11-13 16:57:50]  eth1: no IPv6 routers present
[2011-11-13 17:01:22]  ADDRCONF(NETDEV_UP): eth0: link is not ready
[2011-11-13 17:01:33]  eth1: no IPv6 routers present
[2011-11-13 17:02:04]  ADDRCONF(NETDEV_UP): eth0: link is not ready
[2011-11-13 17:04:47]  ADDRCONF(NETDEV_UP): eth0: link is not ready
[2011-11-13 17:04:54]  type=1400 audit(1321200294.812:28): apparmor="DENIED" operation="open" parent=9097 profile="/sbin/dhclient" name="/var/lib/wicd/dhclient.conf" pid=9139 comm="dhclient" requested_mask="r" denied_mask="r" fsuid=0 ouid=0
[2011-11-13 17:04:58]  eth1: no IPv6 routers present
[2011-11-13 17:08:16]  airo(eth1): link lost (missed beacons)


And if you prefer python this is a solution for this language:

#!/usr/bin/env python
# coding=utf8
 
# Copyright (C) 2010 Saúl ibarra Corretgé <[email protected]>
#
 
"""
pydmesg: dmesg with human-readable timestamps
"""
 
from __future__ import with_statement
 
import re
import subprocess
import sys
 
from datetime import datetime, timedelta
 
_datetime_format = "%Y-%m-%d %H:%M:%S"
_dmesg_line_regex = re.compile("^\[(?P<time>\d+\.\d+)\](?P<line>.*)$")
 
def exec_process(cmdline, silent, input=None, **kwargs):
    """Execute a subprocess and returns the returncode, stdout buffer and stderr buffer.
       Optionally prints stdout and stderr while running."""
    try:
        sub = subprocess.Popen(cmdline, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, **kwargs)
        stdout, stderr = sub.communicate(input=input)
        returncode = sub.returncode
        if not silent:
            sys.stdout.write(stdout)
            sys.stderr.write(stderr)
    except OSError,e:
        if e.errno == 2:
            raise RuntimeError('"%s" is not present on this system' % cmdline[0])
        else:
            raise
    if returncode != 0:
        raise RuntimeError('Got return value %d while executing "%s", stderr output was:\n%s' % (returncode, " ".join(cmdline), stderr.rstrip("\n")))
    return stdout
 
def human_dmesg():
    now = datetime.now()
    uptime_diff = None
    try:
        with open('/proc/uptime') as f:
            uptime_diff = f.read().strip().split()[0]
    except IndexError:
        return
    else:
        try:
            uptime = now - timedelta(seconds=int(uptime_diff.split('.')[0]), microseconds=int(uptime_diff.split('.')[1]))
        except IndexError:
            return
 
    dmesg_data = exec_process(['dmesg'], True)
    for line in dmesg_data.split('\n'):
        if not line:
            continue
        match = _dmesg_line_regex.match(line)
        if match:
            try:
                seconds = int(match.groupdict().get('time', '').split('.')[0])
                nanoseconds = int(match.groupdict().get('time', '').split('.')[1])
                microseconds = int(round(nanoseconds * 0.001))
                line = match.groupdict().get('line', '')
                t = uptime + timedelta(seconds=seconds, microseconds=microseconds)
            except IndexError:
                pass
            else:
                print "[%s]%s" % (t.strftime(_datetime_format), line)
 
if __name__ == '__main__':
    human_dmesg()

Copy and paste or download the code from here.
Run the script and once again you’ll get the result that we want:

[2011-11-13 18:37:19] airo(eth1): link lost (missed beacons)
[2011-11-13 18:38:29] airo(eth1): link lost (missed beacons)
[2011-11-13 18:38:44] ADDRCONF(NETDEV_UP): eth0: link is not ready
[2011-11-13 18:38:52] ADDRCONF(NETDEV_UP): eth0: link is not ready
[2011-11-13 18:39:03] eth1: no IPv6 routers present
[2011-11-13 18:39:07] type=1400 audit(1321205948.113:29): apparmor="DENIED" operation="open" parent=13015 profile="/sbin/dhclient" name="/var/lib/wicd/dhclient.conf" pid=13067 comm="dhclient" requested_mask="r" denied_mask="r" fsuid=0 ouid=0
[2011-11-13 19:22:46] airo(eth1): link lost (missed beacons)

Conclusions

It seem my problem is related to apparmor and some configuration missing for wicd, so at the moment i’ve add in /etc/apparmor.d/sbin.dhclient an entry:

# wicd
  /var/lib/wicd/* r,

And restarted apparmor, let’s see if this works out.

Popular Posts:

Flattr this!

  29 Responses to “How to make dmesg timestamp human readable”

  1. dmesg -T works for me..

    • But not for me.

      • Older versions of dmesg do not have this option. To upgrade dmesg, you need to upgrade the “util-linux” package (Debian based distros). After updating your apt cache, run “sudo apt-get install util-linux”. Dmesg options become:


        $ dmesg --help

        Usage:
        dmesg [options]

        Options:
        -C, --clear clear the kernel ring buffer
        -c, --read-clear read and clear all messages
        -D, --console-off disable printing messages to console
        -d, --show-delta show time delta between printed messages
        -E, --console-on enable printing messages to console
        -f, --facility restrict output to defined facilities
        -h, --help display this help and exit
        -k, --kernel display kernel messages
        -l, --level restrict output to defined levels
        -n, --console-level set level of messages printed to console
        -r, --raw print the raw message buffer
        -s, --buffer-size buffer size to query the kernel ring buffer
        -T, --ctime show human readable timestamp (could be
        inaccurate if you have used SUSPEND/RESUME)
        -t, --notime don't print messages timestamp
        -u, --userspace display userspace messages
        -V, --version output version information and exit
        -x, --decode decode facility and level to readable string

        Supported log facilities:
        kern - kernel messages
        user - random user-level messages
        mail - mail system
        daemon - system daemons
        auth - security/authorization messages
        syslog - messages generated internally by syslogd
        lpr - line printer subsystem
        news - network news subsystem

        Supported log levels (priorities):
        emerg - system is unusable
        alert - action must be taken immediately
        crit - critical conditions
        err - error conditions
        warn - warning conditions
        notice - normal but significant condition
        info - informational
        debug - debug-level messages

  2. Not for me, which version/OS are you using ?

    #dmesg -T
    dmesg: invalid option -- 'T'
    Usage: dmesg [-c] [-n level] [-r] [-s bufsize]
    
  3. alias dmsg_human = dmesg|perl -ne ‘BEGIN{$a= time()- qx!cat /proc/uptime!};s/\[(\d+)\.\d+\]/localtime($1 + $a)/e; print $_;’

  4. Sorry for wrong escaping 😉
    alias dmsg_human=’dmesg|perl -ne “BEGIN{\$a= time()- qx!cat /proc/uptime!};s/\[(\d+)\.\d+\]/localtime(\$1 + \$a)/e; print ;”‘

    • *grrr* even one more copy glitch
      alias dmsg_human=”dmesg|perl -ne \”BEGIN{\\\$a= time()- qx{cat /proc/uptime}};s/\[(\d+)\.\d+\]/localtime(\\\$1 + \\\$a)/e; print \\\$_;\””

      this should work at least.
      Perhaps someone can drop the wrong quouted ones.

      Explanation for perl-dummies 😉

      # use program code from argument line and make an implicit loop to read in stdin.
      perl -ne ‘
      # the BEGIN block is executed only once and directly after perl startup.
      BEGIN{
      # calculate the timestamp of systems startup
      $a= time()- qx{cat /proc/uptime}
      };
      # now for every line
      # substitute the integer part of dmsg timestamp with a human readable value
      s/\[(\d+)\.\d+\]/localtime($1 + $a)/e;
      # and print it out
      print;

      that’s it

  5. its missing to ignore the blanks in front of lower numbers..
    alias tmesg=’dmesg|perl -ne “BEGIN{\$a= time()- qx!cat /proc/uptime!};s/\[\s*(\d+)\.\d+\]/localtime(\$1 + \$a)/e; print \$_;”‘

  6. Because you want to keep the arguments you passed, like dmesg -s 65535, in the perl program you just to adapt this line

    my $dmesg = “/bin/dmesg @ARGV”;

    (By the way, there is a not so user-friendly error about the captcha because i waited too long between the page load and the comment posting.)

  7. There is an error in the python program, there is < and > instead of .

    Plus, i would say that both of the program (perl and python) don’t display an accurate time, i have a ten minute delay here.

  8. Great post.
    dmesg -T works for me two.
    I suggest you update the post and add a note to the first line about this.

  9. Also in bash version:
    base=$(cat /proc/uptime | cut -d ‘.’ -f1); seconds=`date +%s`; dmesg | sed ‘s/^\[\(.*\)\..*\]\(.*\)$/\1\n\2/’ | while read first; do read second; first=`date +”%d/%m/%Y %H:%M:%S” –date=”@$(($seconds – $base + $first))”`; echo “[$first] $second”; done

    • Your bash one-liner looks quite handy. Unfortunately, I am getting these errors:

      -bash: -date=@1362748064: command not found

      Do you happen to know how I can create the Unicode 2013 character before “date” in the segment (…)–date=”@(…), or replace it with something else?

      • I think some characters where translated by the comment system. I hope this works: http://pastebin.com/rWRc8BvQ

        • Yes that works fine, thank you!
          However, the one-liner does not work sometimes. For example:

          original output from dmesg:
          [ 10.097099] e1000 0000:00:03.0: PCI INT A -> Link[LNKC] -> GSI 11 (level, high) -> IRQ 11

          filtered output:
          -bash: 1363079793 – 73723 + 10.097099] e1000 0000:00:03: syntax error: invalid arithmetic operator (error token is “.097099] e1000 0000:00:03”)
          [] -> GSI 11 (level, high) -> IRQ 11

  10. dmesg –help

    -T, –ctime show human readable timestamp (could be
    inaccurate if you have used SUSPEND/RESUME)

  11. Thanks for the post and the examples. This put me on track to write a quick executable in PHP that you can run as a command:

    #!/usr/bin/php
    <?php

    $cmd = '/bin/dmesg';
    $now = time();
    $uptime = shell_exec('/bin/cat /proc/uptime | cut -d\' \' -f1');

    $boot = $now – $uptime;

    print "BOOT TIME: ".date("l, F jS, Y g:i a", $boot)."\n\n";

    foreach ( explode("\n",shell_exec($cmd)) as $l )
    {
    print preg_replace_callback(
    ':\[([\s\d\.]+)\]:',
    function ( $m ) {
    global $boot;
    return '['. date("D M j Y g:ia", $boot + $m[1]) .']';
    },
    $l,
    1) .
    "\n";
    }

  12. Hi , i tried to run the perl script but got some errors

    perl dmesg.pl
    /var/log/dmesg: line 1: syntax error near unexpected token `(‘
    /var/log/dmesg: line 1: `Linux version 2.6.32-cdstv.3.5.0.b215 (cdsbuild@cds-build3) (gcc version 4.1.2 20080704 (Red Hat 4.1.2-44)) #1 SMP Mon Mar 31 14:20:42 PDT 2014’

    When it is taking dmesg 1st line itself it is throwing some error. Could you please help me to solve this issue.

  13. thanks, its work


  14. #!/usr/bin/env ruby
    #

    require 'time'

    $now=Time.new.to_i
    $uptime=%x(cat /proc/uptime | cut -d"." -f1).to_i

    $boot_time=$now-$uptime

    %x(dmesg).split(/\r?\n/).each { |line|
    line.chomp!
    if line =~ /\[\s*(\d+)\.(\d+)\]\s*(.*)/i
    t=Time.at($boot_time+$1.to_i)
    ts=t.strftime("%Y-%m-%d %H:%M:%S")
    puts "[%s] >> %s" % [ ts, $3 ]
    end
    }

  15. Just wanted to point out that none of the above provided scripts working.


    String found where operator expected at ./dmesg_checker.pl line 31, near "OQ "\n""
    (Do you need to predeclare OQ?)
    Missing comma after first argument to join or string function at ./dmesg_checker.pl line 31, near "@dmesg_new )"
    Execution of ./dmesg_checker.pl aborted due to compilation errors.


    Traceback (most recent call last):
    File "./dmesg_checker.py", line 20, in
    _dmesg_line_regex = re.compile("^\[(?P<time>\d+\.\d+)\](?P<line>.*)$")
    File "/usr/lib/python2.7/re.py", line 190, in compile
    return _compile(pattern, flags)
    File "/usr/lib/python2.7/re.py", line 244, in _compile
    raise error, v # invalid expression
    sre_constants.error: unknown specifier: ?P&

  16. dmesg -T works on CentOS 7.3, thanks to all for useful comments.

Leave a Reply to linuxari Cancel reply

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

(required)

(required)

*