in reply to The art of error handling

For the particular example CGI/DBI, I use a custom error-handling subroutine that does all the work for me. The only thing I have to pass (usually) is a simple error code, and perhaps the offencding SQL. For example:
my $dbh = DBI->connect($foo,$bar,$baz,{AutoCommit=>1}) or &Error(1); my $sth = $dbh->prepare($SQL_TEXT) or &Error(2,$SQL_TEXT);
The idea is to pass as little as possible, and let the subroutine deal with it. $DBI::errstr is already global, so it is not passed. The handy dandy caller function tells us exactly where this error came from. The error function then can react different ways, depending on the situation. For most users, it will display a "we are having probems with the database" message, log the error internally somewhere, and exit there (after some quick cleanup, e.g. $dbh->disconnect). For users that are markd as a "developer", a different error message is returned, this one usually has at least $DBI::errstr, the file and line number where it occured, and additional SQL used (formatted for the browser in pretty colors, of course, etc.) One of the biggest advantages to such an approach is the ease in which you can change things - say you want users to see a different message - voila! change it in one place, your error handling routine.

More specific errors, such as the wrong format in the field, should be caught before they go into the database, IMO. Javascript with a safety net of some simple perl checks go a long way towards making this happen. Avoid ever feeding a database "bad" data, as your program will have to rely on the DB's error message to figure out what is going on.

As far as making custom modules, I am a big fan of setting globals. In the case above, it really really helps that DBI sets $DBI::errstr and let's ME (e.g. the script) deal with it how I see fit. Sometimes I use the information inside it, sometimes I don't. I prefer methods that return simply true or false, then set a global.

Replies are listed 'Best First'.
Re: Re: The art of error handling
by markjugg (Curate) on Dec 22, 2000 at 07:22 UTC
    Thanks for the note turnstep,

    I use an error handling system that's very similiar to what you describe. In has input that looks like this:

    %in = ( title => undef, msg => undef, debug => 0, html_action =>1, log_action => 1, death => 1, @_ );
    By default it returns a message in HTML to the user with the title and msg, but you can also turn on debugging output for programmers, and optionally log the error someplace if you want. It differs from your system in at least one significant way:

    Your error handling routine apparently stores the full error messages someplace, so error(1) would expand into something meaningful. This has the drawback that another programmer (or even a forgetful self) would have to go look up the code to see what error was being thrown. This has the advantage of producing short code, and not repeating the same error message, but it's a bit more obfuscated. In my system, the title and message is required for every message, which makes it clear what's happening in the main code line, but it does appear more cluttered, and I end up copying and pasting common errors around. I was thinking of developing a comprise solution: I would just require the title field to be passed. If no msg attribute was present, it would look for default msg in an error hash, with the title as the key. I like this because the key is now a short phrase that will hopefully have some meaning to humans, and be more memorable than a number. However, it allows a succint error handling syntax, and the ability to reuse the text of common error messages.

    -mark