Sample Header Ad - 728x90

Logging with shell script - catch STDERR to log with timestamp

1 vote
2 answers
2104 views
**SOLVED:** A few months ago, I gain interest in logging in shell scripts. The first idea was a manual logging function such as this one:
add2log() {
    printf "$(date)\tINFO\t%s\t%s\n" "$1" "$2" >>"$logPATH"
}
But I wanted to automatise it, such as that STDERR would be automatically logged. It's been some time now that I've found a satisfying answer, and I'm finally taking the time to share it. --------- For each of my shell script, I now use a "main.sh" that holds the log functions as well as the config (setting up log and config files). Here's what it looks like:
#!/bin/bash

###################################################################
# MY HEADERS
###################################################################


#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#~~~~~~~~~~~~~~~~~~Global vars

mainScriptNAME=$(basename "$0")
mainScriptNAME="${mainScriptNAME%.*}"
mainScriptDIR=$(dirname "$0")
version="v0.0"
scriptsDIR="$mainScriptDIR/SCRIPTS"
addonsDIR="$mainScriptDIR/ADDONS"


#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#~~~~~~~~~~~~~~~~~~LOGGER FUNCS

manualLogger() {

    # $1=PRIORITY $2=FUNCNAME $3=message
    printf "$(date)\t%s\t%s()\t%s\n" "$1" "$2" "$3" >>"$logFilePATH"
}

stdoutLogger() {

    # $1=message
    printf "$(date)\tSTDOUT\t%s\n" "$1" >>"$logFilePATH"
}

stderrLogger() {

    # $1=message
    printf "$(date)\tSTDERR\t%s\n" "$1" >>"$logFilePATH"
}


#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#~~~~~~~~~~~~~~~~~~LOG & CONF

createLog() {
    # code to set and touch logFilePATH & confFilePATH
    manualLogger "INFO" "${FUNCNAME}" "Log file created."
}


#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#~~~~~~~~~~~~~~~~~~MAIN

#
createLog

#run scripts
{

    #
    source "$scriptsDIR/file1.sh"
    doSomthing1
    doSomthing2

    #
    source "$scriptsDIR/file2.sh"
    anotherFunction1
    anotherFunction2

    ...


} 2> >(while read -r line; do stderrLogger "$line"; done) \
1> >(while read -r line; do stdoutLogger "$line"; done)
In other words: - all scripts/functions I want to run are in separate files in a ./SCRIPTS folder (so my main.sh is almost always the same) - I call all these scripts in a group { ... } to catch their STDOUT and STDERR - their STDOUT and STDERR are redirect to their respective logger functions The log file looks like this (examples of one manual logger, one STDOUT logger, one STDERR logger):
Lun 23 mai 2022 12:20:42 CEST	INFO	createLog()	Log file created.
Lun 23 mai 2022 12:20:42 CEST	STDOUT	Some standard output
Lun 23 mai 2022 12:20:42 CEST	STDERR	ls: sadsdasd: No such file or directory
The group makes it that ALL output is gathered in log. Instead, you obviously could use the redirect 2> >(while read ... and 1> >(while read ... as you wish for each function. Such as doSomthing1 as its STDOUT and STDERR going to log, but doSomthing2 only has its STDERR redirect.
Asked by YvUh (31 rep)
Feb 28, 2022, 04:04 PM
Last activity: Aug 10, 2025, 04:05 AM