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

A simple question (I hope). I'm working with an automated file transfer system and use Perl programs extensively to run the processes. I'm wondering if it is possible to have the die() function do some actions before it completely dies. Such as saving a copy of the log file and send out a page to let us know that something blew up. I'm not completely familiar with the die() but from what I've read, I haven't seen anything to say if it is possible or not.

Thanks in advance.

"Ex libris un peut de tout"

Replies are listed 'Best First'.
Re: die function and notifications
by broquaint (Abbot) on May 22, 2003 at 14:51 UTC
    I'm wondering if it is possible to have the die() function do some actions before it completely dies.
    As long as you're careful you create a $SIG{__DIE__} handler to do what you want e.g
    $SIG{__DIE__} = sub { print "and the rest was silence ...\n" }; die(); __output__ and the rest was silence ... Died at - line 2.
    Check out Argument stringification in __WARN__ and __DIE__ and Re: How "safe" is die() in %SIG? for some info on the foibles of using the $SIG{__DIE__} handler.
    HTH

    _________
    broquaint

Re: die function and notifications
by jdporter (Paladin) on May 22, 2003 at 14:44 UTC
    That's an awful lot to ask of an at-exit handler. The problem is, what if something in that sequence -- sending out a page, for example -- has an error itself?

    Instead, I'd recommend that you wrap the "main" part of the program in an eval, which will trap any dies that occur in it. Then you can handle those errors in the main flow of the program, rather than in an at-exit (i.e. END) handler.

    jdporter
    The 6th Rule of Perl Club is -- There is no Rule #6.

Re: die function and notifications
by physi (Friar) on May 22, 2003 at 15:36 UTC
    You can also do your clean-up in the END block:
    #!/usr/bin/perl die("Die just another day!\n"); END {print "Still alive to clean up\n"}
    -----------------------------------
    --the good, the bad and the physi--
    -----------------------------------
    
      This is what I've ended up doing. I test for the return code of a call to an external program and if that returns a non-zero, I die and pass the return code to the END from die. Then, within the END, I test $? to see if it is greater than zero, if it is, then I copy the log with an error message and send an alert. Otherwise I copy the log with a different name and exit completely with a 0. This may be kludgy but it seems to work (for the moment). using eval() and $@ does not work so well because I can't get the error messages into $@ (at least not yet).

      &My::custom_routine("TESTTRANSFER"); my $rc=$?>>8; die ($rc) if ($rc > 0); END { if ($? > 0) { print STDERR "TEST.PL Died with error.\n"; copy("TEST.LOG", "TEST.ERROR"); &My::pager("TEST ERROR MESSAGE."); }else{ print STDERR "TEST.PL completed successfully.\n"; copy("TEST.LOG", "TEST.GOOD"); exit 0; } }

      Thanks for the help.

      "Ex libris un peut de tout"

Re: die function and notifications
by dpuu (Chaplain) on May 22, 2003 at 15:08 UTC
Re: die function and notifications
by jaa (Friar) on May 22, 2003 at 15:19 UTC

    All interesting suggestions so far - but we found too many issues with setting up DIE signal handlers for us to trust it in production.

    What we ended up doing, as we had a LOT of legacy stuff, some not written in Perl, was to write a Perl program we call 'run' and use this to execute ALL our stuff - a wrapper for all our processing.

    The RUN program uses the open3() function to run the process as a child, and captures all STDOUT and STDERR as well as hooking its own STDIN into the child.

    Yes - *NIX specific - havent had to do any large processing on NT

    RUN checks exit status, signal and core flags of the child process, and sends us an email if the exit is non-zero

    RUN is great for enforcing a standardised environment on the child processes - we never have issues running stuff on production because something in the environment or path is missing, not-found etc etc

    RUN is also great for preventing cron output from generating unexpected mail - instead, if not running under a tty, it redirects all the output into log files in /var/log

    Regards

    Jeff

      incidentally, we also use the singleton pattern for our Log class - and use this instead of print - it adds PID, date, time etc to all the lines, manages the logging detail level - (error, warn, general, debug, dump)

      And the Log has a DESTROY that gets called when the singleton instance is destroyed - ie at the end of program, were we do some tidy-up, including emailing our support group if any ERROR or WARNING messages were logged.

      It also provides a logFatal() method, which logs a message, sends an email and does a POSIX::_exit($exitval)

      HIH

      The reason we use POSIX::_exit() is that we are running on *NIX with the buggy GCC 2.95 - a task that runs for 5 minutes, creating hashes of about 200MB takes 20-30 minutes for garbage collection - the POSIX::_exit() exits immediately.

      All interesting suggestions so far - but we found too many issues with setting up DIE signal handlers for us to trust it in production

      I have production code doing the type of logging you want to do (along with email notification of failure results, full stack traces and win32::eventlog support.) So im curious as to which "issues" you encountered. I attach $SIG{__WARN__} and $SIG{__DIE__} handlers, and ive had no problems.


      ---
      demerphq

      <Elian> And I do take a kind of perverse pleasure in having an OO assembly language...
Re: die function and notifications
by nimdokk (Vicar) on May 22, 2003 at 15:20 UTC
    Thanks for the replies, this gives me a good direction to look in.

    "Ex libris un peut de tout"