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

Principal Product Manager at Oracle
Ludovico is a member of the Oracle Database High Availability (HA), Scalability & Maximum Availability Architecture (MAA) Product Management team in Oracle. He focuses on Oracle Data Guard, Flashback technologies, and Cloud MAA.

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

  1. Nice article, but I need to do some work because I use ksh, and I don’t understand the use of “sleep 0.2”, until ash only accepts integer values.

    Can you give me some help on that?

    Thanks!

    • Hi Daniel, sleep in bash does accept rational values. I’m sorry, but I can’t help you with ksh. I was used to it many years ago but I can’t recall the last time I used it. Also, the title of the blog post says it all 😉 It’s Bash tips, not KSH tips 🙂

  2. Nice article.
    I was wondering if it is a good practice to set these script as common.sh then include them in all scripts ?
    Anyhow, that’s what I tried to do but never managed to make it work :-/
    Would it be possible to update from your side ?

  3. 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.

  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” “

    • 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.

  5. 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

    • 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

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

Leave a Reply

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

This site uses Akismet to reduce spam. Learn how your comment data is processed.