Cron job stderr email and log file?

I have a cron job:

$SP_s/StartDailyS1.sh >$LP_s/MirrorLogS1.txt 

Where SP_s is the path to the script, and LP_s is the path to the log file. This sends stdout to the log file and stderr to my email address.

Like me:
1) send both stdout AND stderr files to the log file,
2) And send stderr by email

or else: stderr for both the log file and email, and stdout only for the log file.

UPDATE: None of the answers that I have received so far meet the criteria that I have set out or are not suitable for the CRON task.

I saw this, which is designed to "send STDOUT and STDERR from one command to one file, and then only STDERR to another file" (published by zazzybob on unix.com), which seems like what I want to do, and I was wondering Does he inspire someone smarter than me:

 (( my_command 3>&1 1>&2 2>&3 ) | tee error_only.log ) > all.log 2>&1 

I want cron to send STDERR to an email address and not to another file.

+4
source share
8 answers

My experience (ubuntu) is that "crontab" only sends "stderr" messages (I have an output directed to a log file, which is then archived). This is useful, but I wanted to get confirmation that the script worked (even if there were no errors in "stderr") and some details about how much time had passed, which I consider to be a good way to detect a potential problem.

I found a way that I could most easily wrap my head around this problem, was to write a script with some duplicate echo in it. Extensive regular echo ends in a log file. For the important error bits that I want in the crontab email "MAILTO", I used an "echo" which is directed to stderr using "1> & 2".

In this way:

  Frmt_s="+>>%y%m%d %H%M%S($HOSTNAME): " # =Format of timestamp: "<YYMMDD HHMMSS>(<machine name>): " echo `date "$Frmt_s"`"'$0' started." # '$0' is path & filename echo `date "$Frmt_s"`"'$0' started." 1>&2 # message to stderr # REPORT: echo "" echo "================================================" echo "================================================" 1>&2 # message to stderr TotalMins_i=$(( TotalSecs_i / 60 )) # calculate elapsed mins RemainderSecs_i=$(( TotalSecs_i-(TotalMins_i*60) )) Title_s="TOTAL run time" Summary_s=$Summary_s$'\n'$(printf "%-20s%3s:%02d" "$Title_s" $TotalMins_i $RemainderSecs_i) echo "$Summary_s" echo "$Summary_s" 1>&2 # message to stderr echo "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" echo "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" 1>&2 # message to stderr echo "" echo `date "$Frmt_s"`"TotalSecs_i: $TotalSecs_i" echo `date "$Frmt_s"`"'$0' concluded." # '$0' is path & filename echo `date "$Frmt_s"`"'$0' concluded." 1>&2 # message to stderr 

Sends me an email containing this (when there are no errors, lines beginning with 'ssh:' and 'rsync:' are not displayed):

 170408 030001(sb03): '/mnt/data1/LoSR/backup_losr_to_elwd.sh' started. ssh: connect to host 000.000.000.000 port 0000: Connection timed out rsync: connection unexpectedly closed (0 bytes received so far) [Receiver] rsync error: unexplained error (code 255) at io.c(226) [Receiver=3.1.0] ssh: connect to host 000.000.000.000 port 0000: Connection timed out rsync: connection unexpectedly closed (0 bytes received so far) [Receiver] rsync error: unexplained error (code 255) at io.c(226) [Receiver=3.1.0] ================================================ S6 SUMMARY (mins:secs): 'Templates' 2:07 'Clients' 2:08 'Backups' 0:10 'Homes' 0:02 'NetAppsS6' 10:19 'TemplatesNew' 0:01 'S6Www' 0:02 'Aabak' 4:44 'Aaldf' 0:01 'ateam.ldf' 0:01 'Aa50Ini' 0:02 'Aadmin50Ini' 0:01 'GenerateTemplates' 0:01 'BackupScripts' 0:01 TOTAL run time 19:40 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 170408 031941(sb03): '/mnt/data1/LoSR/backup_losr_to_elwd.sh' concluded. 

This does not satisfy my original desire to "send both stdout AND stderr to the log file" (stderr, and only the "echo lines" with "1> and 2" go through email; stdout goes to log), but I believe that this better than my originally intended solution, as the email finds me and I don't need to look for problems in the log file.

0
source

Since I was just looking at the info page for tee (trying to figure out how to do the same), I can answer the last bit of this for you.

This is basically:

 (( my_command 3>&1 1>&2 2>&3 ) | tee error_only.log ) > all.log 2>&1 

but replace "error_only.log" with "> (email_command)"

 (( my_command 3>&1 1>&2 2>&3 ) | tee >(/bin/mail -s "SUBJECT" "EMAIL") ) > all.log 2>&1 

Note: according to tee docs this will work in bash, but not in / bin / sh. If you put this in a cron script (e.g. in /etc/cron.daily/), you can simply, but #! / Bin / bash at the top. However, if you put it as a single line in crontab, you may need to wrap it in bash -c ""

+3
source

I don’t know why no one mentioned this.

With CRON, if you specify MAILTO = for crontab users, STDOUT is already mailed.

Example

 [temp]$ sudo crontab -u user1 -l SHELL=/bin/bash PATH=/sbin:/bin:/usr/sbin:/usr/bin MAILTO=user1 # transfer order shipping file every 3 minutes past the quarter hour 3,19,33,48 * * * * /home/user1/.bin/trans.sh 
+3
source

If you can do stdout / err in separate files, this should do:

 ($SP_s/StartDailyS1.sh 2>&1 >$LP_s/MirrorLogS1.txt.stdout) | tee $LP_s/MirrorLogS1.txt.stderr 
+2
source

If I am missing something:

 command 2>&1 >> file.log | tee -a file.log 

2> & 1 redirects stderr to stdout

β†’ redirects the regular stdout command to the log file

| tee duplicates stderr (from 2> and 1) to register the file and transfers it before sending stdout using cron to MAILTO

I tested it with

 (echo Hello & echo 1>&2 World) 2>&1 >> x | tee -ax 

What World really shows in the console and both texts inside x

The ugly thing is the duplicate file name. And other buffering from stdout / stderr can make the text in the .log file a bit messy, I think.

+1
source

It’s a bit complicated if you want stdout and stderr to be combined into one file, and stderr still enters its own stream.

This should be done (error checking, cleaning and generalized reliability are excluded):

 #! /bin/sh CMD=..../StartDailyS1.sh LOGFILE=..../MirrorLogS1.txt FIFO=/tmp/fifo >$LOGFILE mkfifo $FIFO 2>/dev/null || : tee < $FIFO -a $LOGFILE >&2 & $CMD 2>$FIFO >>$LOGFILE 

stderr is sent to the named pipe, which matches tee(1) , where it is added to the log file (which also added your stdout command), and tee'd returns to the regular stderr.

0
source

I assume you are using bash, you are redirecting stdout and stderr like that

 1> LOG_FILE 2> LOG_FILE 

send an email containing stderr in the body, something like this

 2> MESSAGE_FILE /bin/mail -s "SUBJECT" "EMAIL_ADDRESS" < MESSAGE_FILE 

I’m not sure that you can do above with just one pass, like this

 /bin/mail -s "SUBJECT" "EMAIL_ADDRESS" <2 
-1
source

You can try writing another cronjob to read the log file and "display" the log (in fact, just let cron send it to you)

-1
source

All Articles