Beefy Boxes and Bandwidth Generously Provided by pair Networks
The stupid question is the question not asked
 
PerlMonks  

Have script send email if it dies

by bennymack (Pilgrim)
on Jul 20, 2006 at 17:42 UTC ( [id://562652]=perlquestion: print w/replies, xml ) Need Help??

bennymack has asked for the wisdom of the Perl Monks concerning the following question:

Dear Monks,

What is the best way to have a script send an email if it dies due to some error?

I'm more interested in the "die" part of the question than the sending email part which is no problem.

Is there a module or a particular Perl hack that is well suited for this purpose? Thanks!

Replies are listed 'Best First'.
Re: Have script send email if it dies
by Hue-Bond (Priest) on Jul 20, 2006 at 17:46 UTC

    Tested:

    { local $SIG{'__DIE__'} = sub { ## insert here whatever way of sending a mail you prefer. For exam +ple: open my $mail, '|mail user@localhost' or die "open: $!"; print $mail shift; close $mail; }; die "dying...\n"; }

    --
    David Serrano

Re: Have script send email if it dies
by roboticus (Chancellor) on Jul 21, 2006 at 00:53 UTC
    bennymack:

    While sgifford offers a good solution, I thought I'd offer up one I use periodically. I often have a "watchdog" process running whose only job is to send EMails when it detects that something has gone awry. This has the added benefit of catching (some) scripts that hang in infinite loops.

    My usual method is to have the simple watchdog just watch a directory. If it ever notices a file over X seconds old, it EMails it to you. So any script that wants to take advantage of it may simply put a formatted message in the watched directory, and "touch" it periodically to ensure that it's not too old. If the script dies, watchdog sends it to you when it ages out. If the script hangs without touching the file, the watchdog will still send you the EMail. But you're still scrood if the script hangs in a loop continuously touching the file.

    I don't have the exact code in front of me at the moment, but it's something like this:

    #!/usr/bin/perl -w use warnings; use strict; ############### # CONFIG VARS # ############### my $dir_to_watch = "/cygdrive/c/WATCHDOG"; my $timeout = 120; # Max file age (sec) my $awhile = 30; # Checking interval (sec) #-------------------------------------------------- # Sends contents of specified file to admin sub send_msg { my $fn = shift; print "You'd send $fn via EMail here...\n"; } chdir $dir_to_watch; while (1) { for (`ls`) { chomp; my $age = time - (stat)[9]; send_msg($_) if $age > $timeout; } sleep $awhile; }
    (The code above is tested, except it doesn't send EMail. Plug appropriate code into send_msg.)

    Then my programs (C++, etc.) and scripts use it by formatting an appropriate message to deliver on failure, and update it periodically, like:

    #!/usr/bin/perl -w use warnings; use strict; ############### # CONFIG VARS # ############### my $awhile = 45; # Checking interval (sec) my $my_watched_file = "/cygdrive/c/WATCHDOG/foobar"; my $EMailText= 'To: roboticus@a.fake.domain.com Subject: JobToMonitor.pl fault! Yecch! '; #-------------------------------------------------- # Let watchdog know we're alive... sub still_alive { open OF, '>>', $my_watched_file; print OF $EMailText; close OF; } unlink $my_watched_file; my $next_time = 0; my $count = 0; while ($count < 999999999999) { # put this in a part that's likely to be OK if (time > $next_time) { &still_alive; $next_time = time + $awhile; } # smallish chunks of job that shouldn't take # too much time ++$count; # You can even use it for periodic logging! $EMailText = "$count reached at " . (localtime) . "\n" if $count % 1000000 == 0; } # Don't alert if we complete successfully unlink $my_watched_file;
    Yeah, it's admittedly contrived, but it's a handy thing for servers running lots of odd jobs.

    --roboticus

Re: Have script send email if it dies
by sgifford (Prior) on Jul 20, 2006 at 20:44 UTC
    I would recommend using a very small wrapper program which runs the script, collects any error output, and if it finds any and/or the script exits nonzero, sends the mail. Otherwise there are some situations, like the perl interpreter crashing or running out of memory, that won't generate an email.
Re: Have script send email if it dies
by neilwatson (Priest) on Jul 20, 2006 at 20:00 UTC
    This node sends dies to syslog. You could modifiy it to send an email instead.

    Neil Watson
    watson-wilson.ca

Re: Have script send email if it dies
by Asim (Hermit) on Jul 21, 2006 at 12:57 UTC

    More complex, yet also more robust (in my opinion) is to use Log::Log4perl along with Log::Dispatch::Email::MailSender, which does the trick well in my production code. Here's an example of how it captures the die for logging; you'd configure for emailing elsewhere, and the docs explain how:

    $SIG{__DIE__} = sub { $Log::Log4perl::caller_depth++; my $logger = get_logger("YOUR_LOGGER_HERE"); $logger->fatal(@_); die @_; # Now terminate really };

    This code is originally from the Log::Log4perl FAQ. The nice thing about using a logger, is that you can have it track "state"; sometimes simply having the dying error message isn't enough to track down an issue.

    slight edit for clarification of email portion.

    ----Asim, known to some as Woodrow.

      As sgifford pointed out, this won't catch errors in perl; running out of memory, etc. whereas an external monitoring program will. That's probably the most robust solution.

      Your logging code can then generate whatever output you want, and you'll only get an email describing the code state when the program terminates abnormally (dies, exits with an error status, etc.)

        ...this won't catch errors in perl; running out of memory, etc. whereas an external monitoring program will. That's probably the most robust solution.

        You're correct; my focus was on solutions "within the script", actually. Thanks for the note!

        ----Asim, known to some as Woodrow.

Re: Have script send email if it dies
by raafschild (Novice) on Jul 21, 2006 at 11:58 UTC
    You can use eval in the same way as try/catch in Java.
    eval { # do something that might go wrong $a = 1; $b = 0; print $a/$b; }; if ($@} { print "Something went wrong: $@\n"; }
    Don't forget the ; after the } at the end of eval statement.
Re: Have script send email if it dies
by bravenmd (Sexton) on Jul 24, 2006 at 22:34 UTC
    I like to use bash wrappers that run the script then based on the return status perform a function such as emails, logging, monitoring, etc.

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://562652]
Approved by McDarren
Front-paged by Marza
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others taking refuge in the Monastery: (4)
As of 2024-04-24 11:58 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found