2

A common way to log crontab task errors looks like below:

1 */8 * * * sh /pseudo_path/test.sh 2>> my_err_log 

It's a concise command, but it can't record the error occurred time, and the path of script file is omitted.

So I wrote an error record function:

PROGNAME=$(readlink -f "$0")
SCRIPT_ERR_LOG_PATH="/pseudo_path/script_err_log"

error_exit()
{
    timestamp="$(date +%Y%m%d-%H:%M:%S)"
    x_info=$(echo "Error_${PROGNAME}:Line_${1:-"null"}_")
    zeta=$x_info$timestamp
    echo "$zeta" >> $SCRIPT_ERR_LOG_PATH
    exit 1
}

This function can log the error occurred time together with the absolute path of the script.
But the defect is, I have to add || error_exit $LINENO at every line of my script to make it work.
Though with vim's bulk substitution it could be much easier, but still it looks like a clumsy solution.

So, is there a smarter way to do the same task?

  • 1
    I would look at redirecting stderr only into a program that adds the timestamp to the line once it receives input. Given the commandline syntax for that is difficult to get right, it is in general easier to make a program that starts the sh /pseudo_path/test.sh that receives stderr and stdout separately and adds timestamps to the lines from stderr and writes them to file, but passes on stdout transparently. Python's subprocess.Popen() combined with .communicate() e.g. works well. – Anthon Jul 30 '15 at 5:07
3

Depending on the quantity of the logging information you're expecting to produce, it might be worth using the standard logger tool to write it to the user syslog in /var/log:

1 */8 * * * /path/to/myprog 2>&1 | logger -p user.debug -t 'myprog'

Here is an example of the output written to /var/log/debug on my Debian-based system:

Jul 31 00:17:09 myserver myprog: test message with user.debug

There are various facility/level pairs available for use. You might want to consider user.notice or user.info or user.debug. Just be aware that some of these may also get written to /var/log/messages and /var/log/syslog.


If you want to differentiate stdout and stderr in your cron job, sending only stderr to the logger, you can use a construct like this, which I'm sure others will improve upon:

1 */8 * * * ( /path/to/myprog 2>&1 1>&3 | logger -p user.debug -t 'myprog' ) 3>&1
4

It looks to me like you're creating a Bash script, so take advantage of Bash's trap builtin. For example:

#!/bin/bash
# vim: ft=sh:tw=75:fo-=t:fo+=rcq:ai:

function error_trap()
{
    local -ir __exit_code__=${1:-$?}
    local __timestamp__

    # Reset the ERR sigspec to its original disposition.
    trap - ERR

    __timestamp__=$( date --rfc-3339=seconds --date=now )

    # Hint...
    #declare -p BASH_LINENO
    #declare -p BASH_COMMAND

    echo "[${__timestamp__}] (Line: ${BASH_LINENO[0]}) :: ERROR :: ${BASH_COMMAND}" >&2

    exit ${__exit_code__}
}

# Register function 'error_trap' as the trap handler for
# the ERR (error) sigspec.
trap "{ error_trap; }" ERR

# Try it out; deliberately crash-and-burn this script.
ls this-does-not-exist

Here's the output I see when I invoke this script:

ls: cannot access this-does-not-exist: No such file or directory
[2015-07-30 01:36:32-05:00] (Line: 24) :: ERROR :: ls this-does-not-exist

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.