14

For example, I can log stderr of one script in this way:

* * * * * run_script.sh > /var/log.txt 2>&1

But I want to log stderr of all scripts in my crontab. I can append > /var/log.txt 2>&1 to all scripts, but it's not good if I have hundreds of scripts in cron. Is there another, more simple way to do this?

3 Answers 3

6

In crontab, you can set MAILTO to point to a mail alias that runs a script. That script would accept a mail message, strip off the headers and other goop, and log the remainder with logger. Since all cron script output is sent to the address specified by MAILTO, you'd capture everything.

Example: in crontab

MAILTO=myalias

In /etc/mail/aliases (assuming you're using sendmail)

myalias:"|/usr/local/bin/my-processing-script.sh"

and have the script strip off the mail headers and process the cron output.

2
  • can you be more specific about setting up the MAILTO, alias, MTA, script, etc?
    – endolith
    Commented Nov 29, 2012 at 2:27
  • 1
    @endolith I've edited the answer to give a basic setup which should work for sendmail and broadly compatible MTAs. You'll have to write the script yourself.
    – Kyle Jones
    Commented Nov 29, 2012 at 3:05
5

Any output produced by a command is sent to the user specified in the MAILTO environment variable as set in the crontab(5) file or, if no MAILTO variable is set (or if this is an at(1) or batch(1) job), to the job's owner. If a command produces no output or if the MAILTO environment variable is set to the empty string, no mail will be sent.

Since it uses local mail, you really don't need to set up anything, or maybe just install mailx if it's not already here. Cron will send you the output, you can save the mail in a file and do many things from there. Trying to modify the way cron works to directly suit your need is not the way to go. If you don't think so, just patch and re-buil cron, call it my_cron and use it instead of cron. And be prepared to eventually keep your my_cron up to date and re-build it often.

Add this at the beginning of all your scripts to log everything and stop at the first error

exec 2>&1 > /var/log/YOUR_LOG_FILE
set -e
3
  • should the redirection order be the opposite? > /var/log/YOUR_LOG_FILE 2>&1 i.e., first redirect stdout to a file and only then redirect stderr to stdout (which now points to the file).
    – jfs
    Commented May 21, 2016 at 8:32
  • 2
    It's pretty crazy that on a minimal server that you need to install a mail service, and possibly a mail client, just to read errors produced by Cron. It feels like an anarchistic design decision. Commented Mar 3, 2019 at 16:15
  • ...especially when it's 2021 and there is still no proper solution to this. Commented May 1, 2022 at 23:00
0

Ryan Ye's script over at https://stackoverflow.com/a/7145618/20774 is useful for this as well, though it does both stdout and stderr.


I have a small script cronlog.sh to do this. The script code

#!/bin/sh
echo "[`date`] Start executing $1"
$@ 2>&1 | sed -e "s/\(.*\)/[`date`] \1/"
echo "[`date`] End executing $1"

Then you could do

cronlog.sh /opt/scripts/sql_fetch >> your_log_file

Example result

cronlog.sh echo 'hello world!'

[Mon Aug 22 04:46:03 CDT 2011] Start executing echo
[Mon Aug 22 04:46:03 CDT 2011] helloworld!
[Mon Aug 22 04:46:03 CDT 2011] End executing echo

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .