How to add a timestamp to bash script log?

392,610

Solution 1

You can pipe the script's output through a loop that prefixes the current date and time:

./script.sh | while IFS= read -r line; do printf '%s %s\n' "$(date)" "$line"; done >>/var/log/logfile

If you'll be using this a lot, it's easy to make a bash function to handle the loop:

adddate() {
    while IFS= read -r line; do
        printf '%s %s\n' "$(date)" "$line";
    done
}

./thisscript.sh | adddate >>/var/log/logfile
./thatscript.sh | adddate >>/var/log/logfile
./theotherscript.sh | adddate >>/var/log/logfile

Solution 2

See ts from the Ubuntu moreutils package:

command | ts

Or, if $command does automatic buffering (requires expect-dev package):

unbuffer command | ts

Solution 3

The date command will provide that information

date -u
Sat Sep 10 22:39:24 UTC 2011

so you can

echo $(date -u) "Some message or other"

is that what you wanted ?

Solution 4

Make a config.sh file

#!/usr/bin/env bash
LOGFILE="/path/to/log.log"
TIMESTAMP=`date "+%Y-%m-%d %H:%M:%S"`

When you need to send to log file use

#!/usr/bin/env bash
source /path/to/config.sh

echo "$TIMESTAMP Say what you are doing" >> $LOGFILE

do_what_you_want >> $LOGFILE

Log file will looks like

2013-02-03 18:22:30 Say what you are doing

So it will be easy to sort by date

Solution 5

You can simply echo the command outputs to the logfile. ie,

echo "`date -u` `./script.sh`" >> /var/log/logfile

It really works :)

Example:

[sparx@E1]$ ./script.sh 
Hello Worldy
[sparx@E1]$ echo "`date -u` `./script.sh`" >> logfile.txt
[sparx@E1]$ cat logfile.txt 
Mon Sep 12 20:18:28 UTC 2011 Hello Worldy
[sparx@E1]$ 
Share:
392,610

Related videos on Youtube

Antonius Bloch
Author by

Antonius Bloch

Hi there. I'd love to share, but "Deny by default". If you can't tie the information I'm spilling on Stack Exchange then you can't use it to triangulate an attack on the systems I'm responsible for. I'm careful with what I post, but you can never be too careful, can you?

Updated on September 18, 2022

Comments

  • Antonius Bloch
    Antonius Bloch over 1 year

    I have a constantly running script that I output to a log file:

    script.sh >> /var/log/logfile
    

    I'd like to add a timestamp before each line that is appended to the log. Like:

    Sat Sep 10 21:33:06 UTC 2011 The server has booted up.  Hmmph.
    

    Is there any jujitsu I can use?

  • Antonius Bloch
    Antonius Bloch over 12 years
    Using the date command was kind of what I had in mind, but I can't really add that to the script itself, so what I'm looking for is a way to change this line: "script.sh >> /var/log/logfile" to append the date.
  • user9517
    user9517 over 12 years
    In that case redirect the output of your script to a named pipe and have a daemon listening for output which takes the script output and adds a date before writing it to a log file. You can probably modify the script I wrote here to do this. I would do it because it interests me but it's late in the UK and I have an early start tomorrow.
  • SparX
    SparX over 12 years
    What are you getting when you execute the command ?
  • cjc
    cjc over 12 years
    My god, people, everyone is doing back tick replacement, named pipes, etc. Just enclose both the date command and the script in parens! The guy who has the function has a legit case if there's multi-line output and the log needs to look pretty with the date on every line, but most of these solutions are overkill that doesn't use shell semantics.
  • Nils
    Nils over 12 years
    What is "IFS= " for?
  • Gordon Davisson
    Gordon Davisson over 12 years
    @Nils it's a trick to prevent read from trimming whitespace at the beginning and and of the line. It sets IFS (bash's Internal Field Separator, basically a list of whitespace characters) to empty for the read command.
  • Nils
    Nils over 12 years
    ...and -r ignores the escape-character "\". This should really work in all cases - great pice of scripting.
  • Gordon Davisson
    Gordon Davisson over 12 years
    @Nils it's not completely bulletproof, since some implementations of echo interpret escape sequences. If you really want it not to mess with the content (other than adding dates), replace the echo command with printf "%s %s\n" "$(date)" "$line"
  • Dave Forgac
    Dave Forgac over 11 years
    That will only add the timestamp once per execution of script.sh. The OP needs a timestamp per line.
  • User
    User over 11 years
    although this doesn't answer the OP question I still found it useful info.
  • stackersunited
    stackersunited about 9 years
    That puts a timestamp before the entire output of ''./script.sh'', not before each line.
  • stackersunited
    stackersunited about 9 years
    Your ''config.sh'' will run ''date'' exactly once, on ''source .../config.sh''.
  • Sanjay Yadav
    Sanjay Yadav almost 9 years
    @ shazbot:Thanks for editing, that was a typo error, i didnt notice.
  • Univers3
    Univers3 over 7 years
    This is so cool!
  • Pablo A
    Pablo A almost 7 years
    You might be interested on a ISO-8601 compliant date/timestamp: date -u +"%Y-%m-%dT%H:%M:%SZ" or maybe more pretty date +"%Y-%m-%d %T".
  • Michael Schaefers
    Michael Schaefers almost 6 years
    while this script works as expected, it spawns a new process (execute date) for each log line, which can be a massive drawback depending on your machine and the amount of logs. I would rather suggest to use ts if available, see the answer from @willem
  • Evan Benn
    Evan Benn over 5 years
    this is because it is bash evaluating "s/^/$(date -R) /" and running date once before sed. Sed is passed a static string.
  • Evan Benn
    Evan Benn over 5 years
    as for the other answer, this is just bash running date once. sed is not updating the time per line.
  • Jason Harrison
    Jason Harrison about 5 years
    your first date command should use single quotes, not double quotes.
  • ND Geek
    ND Geek almost 5 years
    @PabloBianchi date [-u] -Iseconds or date [-u] --iso-8601=seconds will accomplish the same thing without manually recreating the format. Per this question/answer, this has been a documented option since v8.15 of coreutils. It doesn't appear to use a 'Z' for UTC, however, which is mildly annoying IMO.
  • akhan
    akhan over 4 years
    Plain bash: yes | head -5000000 | while read line; do echo $((SECONDS)); done | uniq -c which is much slower than gawk. ts utility has similar performance as bash loop.
  • akhan
    akhan over 4 years
    Perl: yes |head -5000000 |perl -ne 'print localtime."\t".$_' |uniq -c which is slightly slower than awk.
  • Stéphane Gourichon
    Stéphane Gourichon over 4 years
    This answer deserves more attention. Even though using external program date might now be such a performance problem on nowadays machines, when a tool has everything inside, better not complicate with more tools. Plus this answers provide a simple and locally reproducible performance measurement (on my machine I get 700-1000 per second and 150k-170k per second). More answers should be of such quality.
  • kdb
    kdb over 4 years
    @StéphaneGourichon There are actually cases where it can make a huge performance difference still. E.g. I use this construct for adding timing information to stdout with someprogram | while true; do date; done | uniq -c . If a program produces hundreds of lines per second, calling date for each slows the performance down, while using the builtin does not. Though curiously, right now even the builtin produces only about 4000 lines per uniq -c for me... Could be that I tested on Linux back then.
  • Stéphane Gourichon
    Stéphane Gourichon over 4 years
    yes we agree, no repeated external program will be faster. When performance is really important, no repeated bash construct will be even faster. GNU awk based solution may provide the best, see @ChuckCottrill's answer serverfault.com/a/835534/137665 On my machine I get 3.5x speed gain by replacing yes |head -5000000 | while true; do printf '%(%F %T)T\n'; done | uniq -c with yes |head -5000000 | gawk '{ print strftime("[%Y-%m-%d %H:%M:%S]"), $0 }' >> /var/log/logfile .
  • OneCricketeer
    OneCricketeer almost 4 years
    You're missing a close paren
  • mcdave
    mcdave over 3 years
    FYI, unbuffer is in the "expect" package on Arch Linux.
  • Christian
    Christian over 2 years
    This gives a weird result on subcommands with the time bash-3.2$ PS4='\t ' bash-3.2$ echo $(echo hi) hi bash-3.2$ set -x bash-3.2$ echo $(echo hi) 113:18:04 echo hi 13:18:04 echo hi hi
  • Sohail Si
    Sohail Si about 2 years
    How to preserve color?
  • Gordon Davisson
    Gordon Davisson about 2 years
    @SohailSi This shouldn't remove color (i.e. any color-setting terminal control escape sequences), but many commands only output color-setting escape sequences when their output is going directly to a terminal. You may need to tell the command producing the initial output to include color sequences even though its output is going to a pipe (e.g. grep --color=always).
  • Josh Williams
    Josh Williams about 2 years
    Thanks @OneCricketeer missed that
  • Admin
    Admin almost 2 years
    This is great, but it is not available on AL2.