Parsing Daemontools/Multilog dates in Shell Script

I run some servers that use the DJB Daemontools to manage their daemons [1]. This is something I would have changed years ago if given a chance because DJB software always seems to do things in a different way to other Unix software and causes pain. Unfortunately when you have a lot of semi-embedded systems that have intermittent net access it’s really not easy to change things, and having staff who aren’t computer experts who have been trained to use certain DJB software makes it even more difficult.

Daemontools uses multilog [2] to manage it’s logging, this gives dates of the format @400000004deedcea1e4a18d4. While DJB has written a tool to parse this it’s not always convenient, and I don’t want to install DJB software on every system that might be used for reading logs (among other things DJB software is not included in any popular distribution).

George Bernard Shaw says that “All progress depends on the unreasonable man” [3], of course he never participated in a large-scale software development project. In the modern age progress usually depends on people who can work with others, which is why DJB software doesn’t get used much – for every DJB program there is a similar program written by someone else that works about equally well on it’s own and is more than 10* more popular because of better interoperability.

So I wrote the following script to convert DJB dates to regular dates. It takes a DJB format date as the first command-line parameter as I generally just paste the relevant date into a different window. At some future time I may write a program to parse an entire log file and convert all the dates but I haven’t had a need for it yet. I think that I’ve done the hardest work involved in writing such a parser so someone else can use this as a starting point if they have such a need.

set -e
DATE=$(echo $1|cut -c 10-17)
SECS=$(echo -e ibase=16\\n$(echo $DATE|tr "[a-z]" "[A-Z]")|bc)
exec date -d "1970-01-01 $SECS sec utc"

7 comments to Parsing Daemontools/Multilog dates in Shell Script

  • Karl E. Jorgensen

    A small suggestion: This construct is pretty ugly..:

    date -d “1970-01-01 $SECS sec utc”

    With GNU Date, how about:

    date -d @$SECS


  • Or date -ud @$SECS since you want UTC.

  • Matt Palmer

    “DJB software is not included in any popular distribution”

    When did Debian fall out of the “popular distribution” set?

  • etbe

    Matt: Right, I should have checked instead of writing from memory. It seems that daemontools is in main and qmail is in non-free.

  • Actually, Russell, qmail’s now in main, even. Please see:

    Please note also:

    You’ll find the latter detailed further in my knowledgebase’s rundown on all known DNS software for Linux.

    Best Regards,
    Rick Moen

  • Thanks for this, Russ, I’ve often wanted to do this quickly !

    Worth noting for the future though that unlike tai64nlocal, it’s not Y2038-safe.

    I also get a difference of 10 seconds in result. From the time the log entry in question was made, tai64nlocal is correct, the script is wrong.

    $ echo “@400000004dfb36fc060c83ec” | tai64nlocal
    2011-06-17 12:13:54.101483500
    $ /usr/local/bin/tai64decode @400000004dfb36fc060c83ec
    Fri Jun 17 12:14:04 BST 2011

    This seems to stem from the following factlet in Wikipedia: “On January 1, 1972, the initial offset of UTC from TAI was chosen to be 10 seconds, which approximated the total difference which had accumulated since 1958, when TAI was defined equal to UT2”

    I think you need to subtract ten (hex 0A):

    SECS=$(echo -e ibase=16\\n$(echo $DATE|tr “[a-z]” “[A-Z]”) – 0A |bc)

  • IIRC TAI counts leap seconds while POSIX (time_t) doesn’t. You won’t be able to accurately convert between the two without a table of leap seconds. :(