[SOLVED] Add timestamp to log output from bash script – Ask Ubuntu

Issue

This Content is from ask ubuntu. Question asked by Real World

I’m still learning how to write bash scripts so I’ve pieced this script together from a few answers I’ve googled.

#!/bin/bash
set -e
run_receiver(){
  pushd event-receiver
  npm run clean
  npm run build
  node dist/index.js "$@"
  popd
}

run_simulator(){
  pushd simulator
  npm run clean
  npm run build
  node dist/index.js "$@"
  popd
}

run_receiver "$@" | awk '{ print "[receiver]", $0 }' 2>&1 & 
run_simulator "$@" | awk '{ print "[simulator]", $0 }' 2>&1 &
#do other things....

This script is running multiple node applications at the same time and prepending [name] on each so I can identify which command produced each log.

Now I’d like to add the date or some kind of time stamp to each line as well. Can anyone tell me how I can achieve this? Thanks



Solution

First of all, you probably want to have the 2>&1 before the awk since if you want to add the timestamp and name to error messages as well as standard output, that needs to happen first. Otherwise, the standard error messages won’t be seen by awk. So you want:

run_receiver "$@" 2>&1 | awk '{ print "[receiver]", $0 }' & 
run_simulator "$@" 2>&1 | awk '{ print "[simulator]", $0 }' &

Next, for the timestamp, you could use date and pass the output of date as a variable to awk:

run_receiver "$@" 2>&1 | awk -v date="$(date)" '{ print date,"[receiver]", $0 }' & 

But that isn’t really what you want: that would calculate the date once, when awk is launched, so all commands would have the same date stamp. You need to have awk calculate the date on each input line, so you need something a bit more complex:

run_receiver "$@" 2>&1 | 
  awk '{ com="date -Iseconds"; com | getline date; print date,"[receiver]", $0 }' &

That stores date -Iseconds in the variable com and then executes com, passing the output through awk’s getline and storing it in the awk variable date which is then printed. However, the default awk in Ubuntu is actually mawk and mawk buffers its input, so you also need to tell it not to buffer otherwise the timestamps won’t be correct. So you need one more tweak:

run_receiver "$@" 2>&1 | 
  awk -Winteractive '{ 
    com="date -Iseconds"; 
    com | getline date; 
    close(com); 
    print date,"[receiver]", $0 
}' &

This will produce output like this:

[receiver] 2022-09-23T13:33:23+03:00 line 1
[receiver] 2022-09-23T13:33:24+03:00 line 2
[receiver] 2022-09-23T13:33:25+03:00 line 3
[receiver] 2022-09-23T13:33:26+03:00 line 4

You can also use GNU awk (called gawk on Ubuntu) which provides some builtin functions for date manipulation:

run_receiver "$@" 2>&1 | 
    gawk '{ date=strftime("%Y-%m-%d %H:%M:%S"); print "[receiver]",date,$0}' 

Which produces output like this:

[receiver] 2022-09-23 13:35:42 line 1
[receiver] 2022-09-23 13:35:43 line 2
[receiver] 2022-09-23 13:35:44 line 3
[receiver] 2022-09-23 13:35:45 line 4


This Question was asked in askubuntu by Real World and Answered by terdon It is licensed under the terms of CC BY-SA 2.5. - CC BY-SA 3.0. - CC BY-SA 4.0.

people found this article helpful. What about you?