2

I would like a shell script to have all it's output for stdout and stderr logged to an external file with timestamps prepended to each line (plus a few extra items), without changing how the script is called. The output redirection should happen within the script itself. I also should not have to change any existing code in the script or pipe commands individually. Ideally I would only have to add a few lines to the script.

Using these two answers:

I got to a point where it's working on Bash

#! /usr/bin/env bash

CUSTOM_PREFIX1="FancyScript" CUSTOM_PREFIX2="SomeRunID_12-3-4.5" LOG_FILE="/var/log/script.log"

touch $LOG_FILE exec 1>> >(while IFS= read -r line; do printf '[%s] %s %s: %s\n' "$(date '+%Y-%m-%d %H:%M:%S')" "${CUSTOM_PREFIX1}" "${CUSTOM_PREFIX2}" "${line}"; done >> "${LOG_FILE}") exec 2>&1

Script continues...

d echo "Hello"

Running the script above produces no output and the following log file:

# cat /var/log/script.log

[2022-02-23 03:11:45] FancyScript SomeRunID_12-3-4.5: Development/shell_log.sh: line 12: d: command not found [2022-02-23 03:11:45] FancyScript SomeRunID_12-3-4.5: Hello

So far so good, but I want to change two things.

  1. Make it work in POSIX shell (sh) and not depend on Bash. Regular sh doesn't like exec 1>> >(...)
  2. Instead of that long sub process (while IFS= read ....) I want to pipe it to a function within the script itself. Something like pipe_log() {...}
Tuaris
  • 83

3 Answers3

3

I think logger is specifically written for this: writing to the syslog files.

See the logger(1) manual (man logger) and the link to the POSIX specification for that utility above for details.

Kusalananda
  • 333,661
JdeHaan
  • 934
  • This (logger) does the job perfectly. As a nice bonus I can use the OS's syslog to further manage it. – Tuaris Apr 08 '22 at 07:09
0

The most advanced text processing utilities in the Unix toolchest are ex/vi, awk and m4, all from the 70s. None of them have time formatting abilities (though with POSIX awk, you can get the epoch time via srand(), and several implementations of awk or vi have time formatting abilities as extensions).

perl, from the mid-80s however is quite ubiquitous and POSIX didn't have to be involved with its standardisation given that there's only one implementation of it.

So you can always wrap your sh script in:

{

your-script here

} 2>&1 | perl -MPOSIX -pse ' $_ = strftime("[%Y-%m-%dT%T%z]", localtime) . " $prefix$_" ' -- '-|=1' "-prefix=$CUSTOM_PREFIX" >> /path/to/file.log

To timestamp every line.

Note the %z for those timestamps to be unambiguous and post-processable.

-1

The logger I mentioned above is intended for the older syslogging environments. On newer, systemd based systems, the systemd-cat utility is more appropriate:

echo 'my message' | systemd-cat -p info -t /path/to/script/executing/this
JdeHaan
  • 934