I recently noticed that I'm prepending __PACKAGE__ and sub/method name to most croak()'s messages because it makes tracking down errors easier. So I started writing a _croak() wrapper that adds this by default (using caller(1)).
E.g.
sub _croak {
my ($msg) = shift // '';
$msg = (caller 1)[3].': '.$msg
unless ref $msg;
Carp::croak($msg);
};
Now every (textual) exception is attributed both to the point where my module was misused (e.g. bad parameter passed), and to the module itself.
And the question: is there a standard module/technique for this? (Full stack traces aka confess() are overkill most of the time).
Instead of getting croak to add caller information, I let my logger do it. Log4perl let's me set the format for the messages I care to log. croak does its job, and the logger lets me peek at what's going on.
A standard technique is to keep generating simple exceptions, and turn them into stacktraces only when needed by loading Carp::Always::Color from the command-line.
Related
I use Log4perl in one of my applications and created my own appender which inherits from Log::Dispatch::Email because I need some special handling of sendmail. This appender worked for some years now, but today I recognized some weird behavior in which $# doesn't get set as before if I configure Log4perl to use my appender or simply Log::Dispatch::Email itself. I used to catch errors in the following way:
eval { main(); 1; };
if (my $error = $#)
{
log()->error($error);
exit(error_no_success());
}
exit(error_success());
If I remove the mail appender from my Log4perl configuration and my application dies in main, $error gets the message and it gets logged within the alternative. The problem now is that when I configure my own descendant of Log::Dispatch::Email or this abstract base class directly, $# in the above statement is the empty string, resulting in the same error as before isn't recognized anymore. If I write something like eval {} or ... $# is properly available and can be saved. The following works:
my $error = undef;
eval { main(); 1; } or $error = $#;
my $error2 = $#;
if ($error)
{
log()->error($error);
exit(error_no_success());
}
exit(error_success());
$error2 is always the empty string if I configure Log::Dispatch::Email in any way. Of course I don't want to change all my code which uses the first example and used to work before to the second one.
Is there anything wrong with my first example? From my point of view it looks like documented for eval in perldoc and it works without email appenders.
Can you think of any reason why using mail appenders changes the behavior on how or when or whatever Perl sets $# in my second example? Any workarounds? I already had a look at the sources of Log::Dispatch but couldn't find anything obviously interfering with my code.
Thanks for any hints!
With some help over on PerlMonks I finally found the problem: $# is unreliable. I already had similar problems before and localized $# in all my destructors by convention, obviously I missed one, which used to log some debug output. After localizing $# in this destructor before any logging statements, too, my problem got solved and error trapping worked again. I don't know why the problem only got triggered using Log::Dispatch, as the destructor always logged debug statements before, but whatever... Like suggested on PerlMonks, one should switch to use Devel::EvalError in the future.
Let's say, there are two modules is our framework: Handler.pm and Queries.pm
Queries.pm is optional and is being loaded at fastcgi process startup
BEGIN {
&{"check_module_$_"} () foreach (Queries);
}
sub check_module_queries {
...
require Eludia::Content::Queries;
...
}
every module function is loaded in one common namespace
now, there are two functions with same name (setup_page_content) in Handler.pm and Queries.pm
setup_page_content is being called in Handler.pm
It looks like original author suggested that Queries.pm:setup_page_content will be called, whenever Queries.pm is loaded
Sometimes it doesn't happen: traceback (obtained via caller ()) in these cases indicates, that setup_page_content was called from module Handler.pm
I logged %INC just before call and it contains Queries.pm and it full path in these cases
This behaviour is inconsistent and pops like in 2-3% of attempts on production installation, mostly when I send two parallel identical http requests. Due amount of effort to reproduce, I doesn't determine yet, whether it is installation specific.
How it will be decided which version of function with same name will be called?
Is it well-defined behaviour?
There should be a reason, original author wrote the code this way
UPDATE
perl version is v5.10.1 built for x86_64-linux-gnu-thread-multi
UPDATE 2
code: Handler.pm and Queries.pm
Queries.pm loading occurs in check_module_queries (BEGIN {} of Eludia.pm),
loaded for every request using Loader.pm (via use Loader.pm <params>)
I'd like to call Custom.pm:setup_page_content, whenever Custom.pm is loaded
So you'd like to call Custom::setup_page_content when it exists.
if (exists(&Custom::setup_page_content)) {
Custom::setup_page_content(...);
} else {
Handler::setup_page_content(...);
}
Sometimes it doesn't happen.
The total lack of information about this prevents me from commenting. Code? Anything?
Is there a way to 'unload' a module but leave it in %INC?
Loading a module is simply running it. You can't "unrun" code. At best, you can manually undo some of the effects of running it. Whether that includes changing %INC or not is entirely up to you.
When there is a namespace collision, the most recently defined/loaded function will take precedence.
These are not proper modules. These are simply libraries. If you turn them into proper modules with proper name spacing you won't have this issue. You barely need to do anything more than:
package Queries;
sub new {
my $proto = shift;
my $class = ref($proto) || $proto;
my $self = {};
bless ( $self, $class );
return $self;
}
And you'll be well on your way. Of course your program will need a couple changes to actually access the class functions. You can look at exporting to the functions to possibly save some refactoring time.
I have forked the code at github and initiated a pull request that I hope will address your problem.
The behaviour is perfectly defined: when you call PACKAGENAME::function_name, PACKAGENAME::function_name is called. It cannot be more than one PACKAGENAME::function_name at at time.
It is possible to redefine each function so many times as you wish. When you, say, execute some code like
eval "sub PACKAGENAME::function_name {...}";
the function is [re]defined. When you require some .pm file, it's much like eval the string with its content.
If PACKAGENAME is not defined explicitly, the __PACKAGE__ value is used.
So if you remark that the version of setup_page_content is taken from Handler.pm, it must indicate that Handler.pm's content was executed (by use, require, read/eval etc.) after Queries.pm was loaded (for the last time).
So you have to track all events of Handler.pm loading. The easy way is to add some debug print at the start of Handler.pm.
A discussion in another question got me wondering: what do other programming languages' exception systems have that Perl's lacks?
Perl's built-in exceptions are a bit ad-hoc in that they were, like the Perl 5 object system, sort-of bolted on as an afterthought, and they overload other keywords (eval and die) which are not dedicated specifically to exceptions.
The syntax can be a little ugly, compared to languages with builtin try/throw/catch type syntax. I usually do it like this:
eval {
do_something_that_might_barf();
};
if ( my $err = $# ) {
# handle $err here
}
There are several CPAN modules that provide syntactic sugar to add try/catch keywords and to allow the easy declaration of exception class hierarchies and whatnot.
The main problem I see with Perl's exception system is the use of the special global $# to hold the current error, rather than a dedicated catch-type mechanism that might be safer, from a scope perspective, though I've never personally run into any problems with $# getting munged.
The typical method most people have learned to handle exceptions is vulnerable to missing trapped exceptions:
eval { some code here };
if( $# ) { handle exception here };
You can do:
eval { some code here; 1 } or do { handle exception here };
This protects from missing the exception due to $# being clobbered, but it is still vulnerable to losing the value of $#.
To be sure you don't clobber an exception, when you do your eval, you have to localize $#;
eval { local $#; some code here; 1 } or do { handle exception here };
This is all subtle breakage, and prevention requires a lot of esoteric boilerplate.
In most cases this isn't a problem. But I have been burned by exception eating object destructors in real code. Debugging the issue was awful.
The situation is clearly bad. Look at all the modules on CPAN built provide decent exception handling.
Overwhelming responses in favor of Try::Tiny combined with the fact that Try::Tiny is not "too clever by half", have convinced me to try it out. Things like TryCatch and Exception::Class::TryCatch, Error, and on and on are too complex for me to trust. Try::Tiny is a step in the right direction, but I still don't have a lightweight exception class to use.
Try::Tiny (or modules built on top of it) is the only correct way to deal with exceptions in Perl 5. The issues involved are subtle, but the linked article explains them in detail.
Here's how to use it:
use Try::Tiny;
try {
my $code = 'goes here';
succeed() or die 'with an error';
}
catch {
say "OH NOES, YOUR PROGRAM HAZ ERROR: $_";
};
eval and $# are moving parts you don't need to concern yourself with.
Some people think this is a kludge, but having read the implementations of other languages (as well as Perl 5), it's no different than any other. There is just the $# moving part that you can get your hand caught in... but as with other pieces of machinery with exposed moving parts... if you don't touch it, it won't rip off your fingers. So use Try::Tiny and keep your typing speed up ;)
Some exception classes, e.g. Error, cannot handle flow control from within try/catch blocks. This leads to subtle errors:
use strict; use warnings;
use Error qw(:try);
foreach my $blah (#somelist)
{
try
{
somemethod($blah);
}
catch Error with
{
my $exception = shift;
warn "error while processing $blah: " . $exception->stacktrace();
next; # bzzt, this will not do what you want it to!!!
};
# do more stuff...
}
The workaround is to use a state variable and check that outside the try/catch block, which to me looks horribly like stinky n00b code.
Two other "gotchas" in Error (both of which have caused me grief as they are horrible to debug if you haven't run into this before):
use strict; use warnings;
try
{
# do something
}
catch Error with
{
# handle the exception
}
Looks sensible, right? This code compiles, but leads to bizarre and unpredictable errors. The problems are:
use Error qw(:try) was omitted, so the try {}... block will be misparsed (you may or may not see a warning, depending on the rest of your code)
missing semicolon after the catch block! Unintuitive as control blocks do not use semicolons, but in fact try is a prototyped method call.
Oh yeah, that also reminds me that because try, catch etc are method calls, that means that the call stack within those blocks will not be what you expect. (There's actually two extra stack levels because of an internal call inside Error.pm.) Consequently, I have a few modules full of boilerplate code like this, which just adds clutter:
my $errorString;
try
{
$x->do_something();
if ($x->failure())
{
$errorString = 'some diagnostic string';
return; # break out of try block
}
do_more_stuff();
}
catch Error with
{
my $exception = shift;
$errorString = $exception->text();
}
finally
{
local $Carp::CarpLevel += 2;
croak "Could not perform action blah on " . $x->name() . ": " . $errorString if $errorString;
};
A problem I recently encountered with the eval exception mechanism has to do with the $SIG{__DIE__} handler. I had -- wrongly -- assumed that this handler only gets called when the Perl interpreter is exited through die() and wanted to use this handler for logging fatal events. It then turned out that I was logging exceptions in library code as fatal errors which clearly was wrong.
The solution was to check for the state of the $^S or $EXCEPTIONS_BEING_CAUGHT variable:
use English;
$SIG{__DIE__} = sub {
if (!$EXCEPTION_BEING_CAUGHT) {
# fatal logging code here
}
};
The problem I see here is that the __DIE__ handler is used in two similar but different situations. That $^S variable very much looks like a late add-on to me. I don't know if this is really the case, though.
With Perl, language and user-written exceptions are combined: both set $#. In other languages language exceptions are separate from user-written exceptions and create a completely separate flow.
You can catch the base of user written exceptions.
If there is My::Exception::one and My::Exception::two
if ($# and $#->isa('My::Exception'))
will catch both.
Remember to catch any non-user exceptions with an else.
elsif ($#)
{
print "Other Error $#\n";
exit;
}
It's also nice to wrap the exception in a sub call the sub to throw it.
In C++ and C#, you can define types that can be thrown, with separate catch blocks that manage each type. Perl type systems have certain niggling issues related to RTTI and inheritance, according from what I read on chomatic's blog.
I'm not sure how other dynamic languages manage exceptions; both C++ and C# are static languages and that bears with it a certain power in the type system.
The philosophical problem is that Perl 5 exceptions are bolted on; they aren't built from the start of the language design as something integral to how Perl is written.
It has been a looong time since I used Perl, so my memory may be fuzzy and/or Perl may have improved, but from what I recall (in comparison with Python, which I use on a daily basis):
since exceptions are a late addition, they are not consistently supported in the core libraries
(Not true; they are not consistently supported in core libraries because the programmers that wrote those libraries don't like exceptions.)
there is no predefined hierarchy of exceptions - you can't catch a related group of exceptions by catching the base class
there is no equivalent of try:... finally:... to define code that will be called regardless of whether an exception was raised or not, e.g. to free up resources.
(finally in Perl is largely unnecessary -- objects' destructors run immediately after scope exit; not whenever there happens to be memory pressure. So you can actually deallocate any non-memory resources in your destructor, and it will work sanely.)
(as far as I can tell) you can only throw strings - you can't throw objects that have additional information
(Completely false. die $object works just as well as die $string.)
you cant get a stack trace showing you where the exception was thrown - in python you get detailed information including the source code for each line in the call stack
(False. perl -MCarp::Always and enjoy.)
it is a butt-ugly kludge.
(Subjective. It's implemented the same way in Perl as it is everywhere else. It just uses differently-named keywords.)
Don't use Exceptions for regular errors. Only Fatal problems that will stop the current execution should die. All other should be handled without die.
Example: Parameter validation of called sub: Don't die at the first problem. Check all other parameters and then decide to stop by returning something or warn and correct the faulty parameters and proceed. That do in test or development mode. But possibly die in production mode. Let the application decide this.
JPR (my CPAN login)
Greetings from Sögel, Germany
I've got a bunch of questions about how people use exceptions in Perl. I've included some background notes on exceptions, skip this if you want, but please take a moment to read the questions and respond to them.
Thanks.
Background on Perl Exceptions
Perl has a very basic built-in exception system that provides a spring-board for more sophisticated usage.
For example die "I ate a bug.\n"; throws an exception with a string assigned to $#.
You can also throw an object, instead of a string: die BadBug->new('I ate a bug.');
You can even install a signal handler to catch the SIGDIE psuedo-signal. Here's a handler that rethrows exceptions as objects if they aren't already.
$SIG{__DIE__} = sub {
my $e = shift;
$e = ExceptionObject->new( $e ) unless blessed $e;
die $e;
}
This pattern is used in a number of CPAN modules. but perlvar says:
Due to an implementation glitch, the
$SIG{DIE} hook is called even
inside an eval(). Do not use this to
rewrite a pending exception in $# , or
as a bizarre substitute for overriding
CORE::GLOBAL::die() . This strange
action at a distance may be fixed in a
future release so that $SIG{DIE}
is only called if your program is
about to exit, as was the original
intent. Any other use is deprecated.
So now I wonder if objectifying exceptions in sigdie is evil.
The Questions
Do you use exception objects? If so, which one and why? If not, why not?
If you don't use exception objects, what would entice you to use them?
If you do use exception objects, what do you hate about them, and what could be better?
Is objectifying exceptions in the DIE handler a bad idea?
Where should I objectify my exceptions? In my eval{} wrapper? In a sigdie handler?
Are there any papers, articles or other resources on exceptions in general and in Perl that you find useful or enlightening.
Cross-posted at Perlmonks.
I don't use exception objects very often; mostly because a string is usually enough and involves less work. This is because there is usually nothing the program can do about the exception. If it could have avoided the exception, it wouldn't have caused it in the first place.
If you can do something about the exceptions, use objects. If you are just going to kill the program (or some subset, say, a web request), save yourself the effort of coming up with an elaborate hierarchy of objects that do nothing more than contain a message.
As for number 4; $SIG{__DIE__} should never be used. It doesn't compose; if one module expects sigdie to work in one way, and another module is loaded that makes it work some other way, those modules can't be used in the same program anymore. So don't do that.
If you want to use objects, just do the very-boring die Object->new( ... ). It may not be exciting as some super-awesome magic somewhere, but it always works and the code does exactly what it says.
I'm working in a large Perl application and would like to get stack traces every time 'die' is called. I'm aware of the Carp module, but I would prefer not to search/replace every instance of 'die' with 'confess'. In addition, I would like full stack traces for errors in Perl modules or the Perl interpreter itself, and obviously I can't change those to use Carp.
So, is there a way for me to modify the 'die' function at runtime so that it behaves like 'confess'? Or, is there a Perl interpreter setting that will throw full stack traces from 'die'?
Use Devel::SimpleTrace or Carp::Always and they'll do what you're asking for without any hard work on your part. They have global effect, which means they can easily be added for just one run on the commandline using e.g. -MDevel::SimpleTrace.
What about setting a __DIE__ signal handler? Something like
$SIG{__DIE__} = sub { Carp::confess #_ };
at the top of your script? See perlvar %SIG for more information.
I usually only want to replace the dies in a bit of code, so I localize the __DIE__ handler:
{
use Carp;
local $SIG{__DIE__} = \&Carp::confess;
....
}
As a development tool this can work, but some modules play tricks with this to get their features to work. Those features may break in odd ways when you override the handler they were expecting. It's not a good practice, but it happens sometimes.
The Error module will convert all dies to Error::Simple objects, which contain a full stacktrace (the constructor parses the "at file... line.." text and creates a stack trace). You can use an arbitrary object (generally subclassed from Error::Simple) to handle errors with the $Error::ObjectifyCallback preference.
This is especially handy if you commonly throw around exceptions of other types to signal other events, as then you just add a handler for Error::Simple (or whatever other class you are using for errors) and have it dump its stacktrace or perform specialized logging depending on the type of error.