Bash tips & tricks [ep. 5]: Write the output to a logfile

This is the fifth epidose of a small series.

Description:

Logging the output of the scripts to a file is very important. There are several ways to achieve it, I will just show one of my favorites.

BAD:

You can log badly either from the script to a log file:

or by redirecting badly the standard output of the script:

 GOOD:

My favorite solution is to automatically open a pipe that will receive from the standard output and redirect to the logfile. With this solution, I can programmatically define my logfile name inside the script (based on the script name and input parameters for example) and forget about redirecting the output everytime that I run a command.

(*) the functions edebug, einfo, etc, have to be created using the guidelines I have used in this post: Bash tips & tricks [ep. 4]: Use logging levels

The -Z parameter can be used to intentionally avoid logging.

Again, all this stuff (function definitions and variables) should be put in a global include file.

If I execute it:

 

The following two tabs change content below.

Ludovico

Oracle ACE Director and Senior Consultant at Trivadis
Ludovico is an Oracle ACE Director, frequent speaker and community contributor, working as Senior Database Specialist for Trivadis, Switzerland.

6 thoughts on “Bash tips & tricks [ep. 5]: Write the output to a logfile

  1. Pingback: Bash tips & tricks [ep. 5]: Write the output to a logfile - Ludovico Caldara - Blogs - triBLOG

  2. hi –

    this is a great series of tips and tricks when it comes to writing shell script. I had one question with regards to this.

    Using the above and also the “F_check_warn” function, how does one go about capturing the actual output of the error… for example if i run below

    Log_Open
    ls /do/not/work
    F_check_warn $? “ls working or not”
    Log_Close

    I would get output like below in my logfile
    2016-09-27 13:50:59 – WARNING – ls working or not failed with exit code 2. The script will continue.

    but the actual error output (like below) will be missed…so how does one capture that?
    ls: cannot access/do/not/work: No such file or directory

  3. Hi max,
    The standard error is not filtered, so if you follow my examples the only way to see the error is in interactive mode…

    Good point!
    actually it’s not so easy…
    I guess you can try to put a wrapper around the command that sets a variable with the error. Then you can display it in the F_check_warn.

    Let’s try:

    function F_check_warn() {
    EXITCODE=$1
    shift
    if [ $EXITCODE -eq 0 ] ; then
    eok $@ succeded with exit code $EXITCODE
    else
    if [ “${_ERRMSG}” ] ; then
    ewarn “STDERR: ${_ERRMSG}”
    fi
    ewarn $@ failed with exit code $EXITCODE. The script will continue.
    fi
    # return the same code so other checks can follow this one inside the script
    return $EXITCODE
    }

    function F_try() {
    cmd=$@
    exec 4>&1
    _ERRMSG=$( { $cmd >&4 ; } 2>&1 )
    return $?
    }

    F_try “ls /not/existing”
    F_check_warn $? “ls working or not”

    THE OUTPUT IS….
    # ./test.sh
    2016-09-27 17:40:08 – WARNING – STDERR: ls: cannot access /not/existing: No such file or directory
    2016-09-27 17:40:08 – WARNING – ls working or not failed with exit code 2. The script will continue.

    Bingo! I think I will introduce this new concept 😉 thanks for the idea

  4. Hello –

    That option will work as long as the command we are trying to run does not have double quotes in it, something like below is sure to break…

    original command
    mysql -uroot -h0 -e “show database”

    after F_try function
    F_try “mysql -uroot -h0 -e “show database” “

  5. also i am not sure if this could be a option but if we do (2>&1).. but this would be required on all commands…

    ls /do/not/work 2>&1
    F_check_warn $? “ls working or not”

    we get something below in the logs…

    2016-09-27 18:02:44 – Logging to /tmp/logs/test_output_20160927_180244.log
    ls: cannot access /tha: No such file or directory
    2016-09-27 18:02:44 – WARNING – ls working or not failed with exit code 2. The script will continue.

  6. You are right. You can add “eval” in order to evaluate correctly the string via bash.
    The good with the F_try approach is that you can automatically enrich it for better debugging.
    E.g.

    function F_try() {
    Command=$@
    edebug “Executing the following command:”
    edebug ” ${Command}
    exec 4>&1
    _ERRMSG=$( { eval ${Command} >&4 ; } 2>&1 )
    return $?
    }

    F_try “ls -ld \”/tmp\””
    F_check_warn $? “ls working or not”

    F_try “ls -ld \”/not/existing\””
    F_check_warn $? “ls working or not”

    OUTPUT:
    # ./test.sh -G
    2016-09-28 15:32:31 – DEBUG — -G specified: Debug mode
    2016-09-28 15:32:31 – DEBUG — Executing the following command:
    2016-09-28 15:32:31 – DEBUG — ls -ld "/tmp"
    drwxrwxrwt. 25 root root 4096 Sep 28 15:32 /tmp
    2016-09-28 15:32:31 – SUCCESS – ls working or not succeded with exit code 0
    2016-09-28 15:32:31 – DEBUG — Executing the following command:
    2016-09-28 15:32:31 – DEBUG — ls -ld "/not/existing"
    2016-09-28 15:32:31 – WARNING – STDERR: ls: cannot access /not/existing: No such file or directory
    2016-09-28 15:32:31 – WARNING – ls working or not failed with exit code 2. The script will continue.
    2016-09-28 15:32:31 – DEBUG — No cleanup function defined.

Leave a Reply

Your email address will not be published. Required fields are marked *