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

I have a requirement in my current project for a simple yet flexible logging facility. While die/croak are fine for exception handling, logging uncaught exceptions to stderr is often too inflexible -- you may want to write fatal errors to an arbitrary file handle/s and/or send an email, for example.

I'm thinking of rolling my own very simple logging/tracing/carping facility (I'm in good company judging by the very many Log and Carp modules on the CPAN ;-). Here's some sample code to show where I'm coming from.

package MyDie; my $die_handle = \*STDOUT; sub mydie { my $message = shift; # If in eval block, throw exception ... $^S and die $message; # ... otherwise print message to handle and exit. print {$die_handle} $message, "exiting now\n"; exit 1; } 1;
and a test driver:
use MyDie; sub testfn { print "in testfn\n"; MyDie::mydie("whoops\n"); print "end testfn\n"; } eval { testfn() }; $@ and print "caught: '$@'\n"; testfn(); print "end test program\n";

Generally, I prefer functions to throw exceptions rather than return special values. The idea here is to simply call die (throw) if called inside an eval block, otherwise to log the fatal error message and exit.

Since there are many ways to skin this particular cat, I'm interested to hear people's ideas and opinions before charging ahead with this.

Replies are listed 'Best First'.
Re: Rolling your own die/carp/croak/logging/exception facility
by rinceWind (Monsignor) on Mar 10, 2006 at 09:02 UTC

    How does Log::Log4perl measure up?

    --

    Oh Lord, won’t you burn me a Knoppix CD ?
    My friends all rate Windows, I must disagree.
    Your powers of persuasion will set them all free,
    So oh Lord, won’t you burn me a Knoppix CD ?
    (Missquoting Janis Joplin)

Re: Rolling your own die/carp/croak/logging/exception facility
by hv (Prior) on Mar 10, 2006 at 12:54 UTC

    I use a handrolled system which works very well for my application. I talked about it a bit at Catching fork() with tied STDERR.

    While I never did find a general solution for the type of problem I discussed there, it hasn't caused me any problems since I found the solution for Email::Valid (ie to stop it forking by installing Net::DNS).

    Until this week I supported 4 levels of logging: die, warn, debug and info. $SIG{__DIE__}, $SIG{__WARN__} are caught to redirect appropriately. Logged messages are split by installation (there are about 50 installations of the application running on the main box), and within an installation 'info' messages go to one file, and all others are split to files named after the program that generated them.

    A cron job sends me a nightly email of any nonempty non-info files - the idea is that any problems logged are resolved and then the log lines relating to the problem cleared down, so that most of the time nothing is listed.

    There is a single utility (called 'log') that makes it all useful: it allows me to list the log files, search for log lines matching particular patterns, clear down matching log lines, or tail selected groups of log files. (I got help with the tail problem at nonblocking I/O - testing whether file has more data to read - it now happily tails 80-odd files with good responsiveness at a processor load of around 0.07.)

    This week I added a new type of log - spammers were regularly coming along to try and find holes in our mailform script, and we wanted a more automated process for handling them that didn't keep generating error logs. So I added an 'abuse' type, logged to a single per-installation file (like info), and a mechanism to block abusers for escalating periods of time.

    Hugo

Re: Rolling your own die/carp/croak/logging/exception facility
by izut (Chaplain) on Mar 10, 2006 at 10:22 UTC

    Someone asked something like this a while. You can check perldoc perlipc about wrapping $SIG{__WARN__} and $SIG{__DIE__}. There's a module I wrote based on an merlyn's article, called Cpan::Mailer which sends an email to one in case warn, die or any Carp functions were called.

    By the way, it is a simple wrapping around the standard way of doing things in Perl, i.e. open() or die();.

    As said before, Log::Log4perl is extensible enough to allow you doing the procedures you need (send an email, log to this or that log file, etc).

    Igor 'izut' Sutton
    your code, your rules.