Re: Style guide for error messages?
by rir (Vicar) on Sep 21, 2005 at 22:22 UTC
|
Perl Best Practices covers this issue well. Objects
are the thing to throw.
I disagree with some of your ideas:
-
Warnings should be meaningful. A warning that needs no
action can be ignored, then will be ignored, then just becomes useless verbiage. Make it an error or silence it.
-
"Fatal errors" are a self defining group. You don't
need to tag them so. Update: I wish I hadn't said that.
It is true, but if you know your exception should
be fatal you should capture that information in the exception.
One just needs to be careful of unwarranted assumptions about the calling environment.
-
Always provide the line number of the error and/or the
caller. If some part of the code doesn't handle input
correctly, you will need to know which code that is.
Like Best Practices I would suggest using objects, in your first pass use the
object type and the long output of a bare croak, in your
message clean up phase use another method to output
the exceptions' error strings. Since these methods or
the table they use doesn't exist the brokenness forces
the fix; examining your type tree gives you a list of all
your errors and their meanings then you just need express them. This
implies handler objects or another way of consolidating
your error handling code.
You may complain that I've only moved your problem to
the naming of exception packages. I won't argue.
Be well,
rir | [reply] |
|
I agree on objects being the thing the throw. (c.f. Exception::Class and my own Exception::Class::TryCatch)
However, even the object carries with it some message that may wind up in front of the user. But if I understand your argument, you're suggesting never bothering to add any error string at the time of the croak -- just the default system output -- and using the description defined in the Exception::Class object as the message instead. That does just push the problem upstream, as it were, but at least it's done only once, and at a time when more thought can be devoted to crafting the message (and it can be parameterized with fields as necessary). That's a good idea. ++
On the other hand, I think it requires overriding the as_string function to stringify as the description plus the right field(s) in case it isn't caught. Lots of up front work, but on a large project, definitely less headache in the long run. E.g., a very brief, quick example:
use Exception::Class (
'FileOpenError' => {
isa => 'Exception::Class::Base',
description => "Error: couldn't open the file called ",
fields => [ 'filename' ],
alias => 'throw_file_open_error',
},
);
BEGIN {
# minimal stringification
*FileOpenError::as_string = sub {
my $self = shift;
return $self->description() . $self->filename();
}
}
# later...
open my $fh, "<", $filename
or throw_file_open_error( filename => $filename );
-xdg
Code written by xdg and posted on PerlMonks is public domain. It is provided as is with no warranties, express or implied, of any kind. Posted code may not have been tested. Use of posted code is at your own risk.
| [reply] [d/l] [select] |
|
I seldomly include the line number in my error messages. The vast majority of my usage of 'die' is after a system command:
open(...) or die(...);
chmod(...) or die(...);
If I can't open a file for some reason (it doesn't exist, I don't have permission, whatever), all I care about is which file did the program try to open, and why can't it open the file. It doesn't matter whether it tried to open the file on line 23, or on line 389 - dies not being caught by eval will report to the user, and should contain only information that's relevant to the user. Line numbers aren't.
The second largest group of die usage are meant as exceptions. Again, line numbers are useless - the die is supposed to be catched (or escalated to a real die), and I need an informative message or datastructure. That's what I'll inspect in $@ - not a line number.
I might want to know line-numbers is during debugging. But croak() already gives a stack-trace, and that is often already enough.
The compiler emitting line-number on syntax error, now that's a useful use of line numbers. | [reply] [d/l] |
|
And I disagree with Perl Best Practices.
The advice in PBP is designed to be one fairly good way to do things. It is not the only possible one, and it is not necessarily the best for all circumstances.
I agree that if you attempt to use exceptions as a flow of control, then it is much better to throw objects than strings. But I'd prefer that exceptions generally be fatal, and would like to discourage trying to use the exception system for complex flow of control. Which means that all of TheDamian's arguments for exception objects are arguments for how to better do what I'd like people not to do.
This is not to say that PBP is wrong. It is correct that it provides an internally consistent set of best practices. But it is not the only possible one, and it is not my preferred one.
| [reply] |
|
This is not to say that PBP is wrong. It is correct that it provides an internally consistent set of best practices. But it is not the only possible one, and it is not my preferred one.
So, naturally, enquiring minds now want to know what you prefer instead! :-)
| [reply] |
|
|
|
|
|
|
... I'd prefer that exceptions generally be fatal, and would like to discourage trying to use the exception system for complex flow of control. Which means that all of TheDamian's arguments for exception objects are arguments for how to better do what I'd like people not to do.
The emotion behind this evokes some fellow feeling but
I don't find much logic in it.
Exceptions are always a flow of control
mechanism.
Exceptions usually are fatal.
Exceptions should be used to clarify flow of control.
And if you must do something, distaste is not a reason
to do it badly.
Exceptions are all about passing control to unknown code.
The type or value of an exception should rarely be needed
by the handler; that is the start of a brittle, tangled mess. I use the type to carry
meaning without being locked into a representation (for
those rare occasions). I use the object to carry a bunch
of diagnostic data.
I use exceptions like a more robust and efficient version
of the LIBNAME_STATUS variables common to old C libraries.
Rarely is there any fine discrimination by the handler, usually just FAILURE vs. SUCCESS.
Be well,
rir
| [reply] |
|
|
|
Re: Style guide for error messages?
by danb (Friar) on Sep 21, 2005 at 22:21 UTC
|
If you use something like Log::Log4Perl, then it can do some of the things you mentioned automatically (prefixes, line numbers).
Where appropriate, I think that hints should be included in the error messages. For example, Error: Incorrect password. Hint: Are you sure your Caps Lock is turned off?
| [reply] [d/l] |
Re: Style guide for error messages?
by ambrus (Abbot) on Sep 21, 2005 at 21:35 UTC
|
My practices are these.
I always make sure that it would be clear from the error message that it's an error. I don't use a single prefix, just include one some word like qw"error cannot failed failure". It can be very confusing if you write
read $FOO, $s, $l or do {
warn "reading foo file";
last PROCESS_FOO;
}
because it will seem to be a status message saying the program is starting to read the foo file.
I always include $! if its value is meaningful (that is, if the function that fails sets it).
I always provide the implicit line number (although I almost always ignore it when I read the error message). The exception is some status messages that are not errors.
I don't capitalize the error message.
I sometimes give details about the error, sometimes not. I add the details in the die statement if the error actually happens and I don't understand why.
If you want to know more about my style, here is the complete (ok, I could have missed some) list of error statements in two of my programs.
| [reply] [d/l] [select] |
Re: Style guide for error messages?
by jplindstrom (Monsignor) on Sep 22, 2005 at 11:17 UTC
|
In addition to your stuff:
/J
| [reply] [d/l] [select] |
Re: Style guide for error messages?
by pg (Canon) on Sep 21, 2005 at 23:21 UTC
|
Cool! Just add one thing: for something you expect to go production and someone else will (evetually) take over and support. Add some brief description to the error message that might help them to determine the solution. This is not always possible, but try your best to help whever possible.
| [reply] |
Re: Style guide for error messages?
by wazoox (Prior) on Mar 09, 2006 at 17:18 UTC
|
I currently use a logging object I wrote to manage messages. When something's going wrong, my rule of the thumb is to write the message to the log object, then to return undef. something like :
use strict;
use warnings;
package bozo;
use Message;
sub failing {
my $log = Message->new ;
$log->set_error("this always fails");
return
}
package main;
use Message;
my $log = Message->new ;
# I sometimes do this
eval { `touch /toto` };
if ($@) { $log->set_error("it failed! : $@") ;
# or this
if ( not 0 ) {
$log->set_error("it failed too!")
}
# now calling the failing sub up there:
if ( not bozo::failing() ) {
print $log->get_message();
}
Whatever I do with the error string, the Message object also spits out errors and messages to the log, this way (PID, date and time, the the message):
[25435] 2006-02-21 14:27:20 : ERROR : DBD::Pg::st execute failed: exec
+ute on disconnected handle at ../lib/Archiver/Job.pm line 96.
| [reply] [d/l] [select] |