$# gets set differently on eval and Log::Dispatch::Email - perl

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.

Related

Capturing stack traces on exceptions with mod_perl

I am converting some cgi scripts to mod_perl. Under cgi, I used a sig DIE to capture stack traces whenever there was an uncaptured exception, and logged them. This worked great: whenever something died in the script, I'd get a nice stack trace in my application logs. Code is:
BEGIN {
$SIG{__DIE__} = \&sigDie;
}
sub sigDie {
return 1 if $^S; # we are in an eval block
my ($error) = #_;
cluck("Caught fatal error: $error"); # put a stack trace in the logs via warn
local $Log::Log4perl::caller_depth = $Log::Log4perl::caller_depth + 1;
FATAL #_; # call log4perl's fatal
return 1;
}
Under Apache2::Registry, however, my code is no longer called, it simply stops logging when it dies. I assumed this was because my code is being eval'ed by mod_perl, but I took the eval check off my routine above and I'm still not getting called.
Is there any way I can get what I want under mod_perl? I have found these automatic logging of stack traces immensely useful and would miss them if I have to forgo them. So far I have come up empty on how to get it.
I don't know the answer, but can think of a few possibilities and ways to check.
Something is wrong with log4perl.
Does a call to FATAL still work outside of a __DIE__ handler?
Errors are not being logged at all.
Remove the die handler, do exceptions get logged?
Something is replacing your $SIG{__DIE__} handler.
Since you're setting it up at BEGIN time, it's possible something either in Apache2::Registry or another program is replacing it. I'd find out by verifying what is in $SIG{__DIE__} just before throwing an error. Perhaps dumping it out with Data::Dump::Streamer, which can handle code refs, you might be able to figure out what's setting it.
A safer, and more polite, way to register a die handler is...
local $SIG{__DIE__} = ...;
...the rest of your program...
This will re-register your handler on each request AND not blow over a global handler outside of its scope.
Hope that helps to figure out what's going on.

Looking for a clearer Carp::croak()

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.

Is it better to croak() or to die() when something bad happens in Perl?

perlcritic complaints that the following code, some boilerplate DBI stuff that works perfectly fine, should croak instead of die:
# Connect to database
my $db_handle = DBI->connect( $url, $user, $password ) or die $DBI::errstr;
All this, while die seems to work fine for me.
I would think for a samurai Perl warrior, croak is less honorable than actually die when things go awry. Jokes apart
Why should I croak instead of die?
What are the consequences of not heeding perlcritic's advice?
From http://www.perlmonks.org/?node_id=685452
You use die when the error is something you or your code didn't do right. You use croak when it's something your caller isn't doing right. die "error: $!" indicates the error is on the line where the error occured. croak "error: $!" indicates the error is on the line where the caller called your code.
In this case, the error (connection error to DB) has nothing to do with the caller and everything to do with the line making the connection, so I would use die.
I usually use the following:
die "string" for fatal messages you want to directly communicate to the user. I mostly do this in scripts.
die $object for full blown exception objects, although most exception classes will have throw method doing that for you. This is for when your caller should be able to tell what kind of error you throw, and maybe even extract information out of it. If you're using Moose, check out Throwable and Throwable-X
croak "message" like Adrian said is for when your user has done something wrong, and you want to report the error at whatever called your code. Functions and API level methods are usual cases for this.
confess "message" for library errors where I don't see the usefulness of an exception yet. These are usually runtime errors you assume to be a mistake, rather than an exceptional condition. It can make sense to use exceptions for these, especially if you have a large project that uses exceptions already. But it's a good, nice and easy way to get a stacktrace with the error.
If we called the die and croak outside the function there is no
difference between these functions.
We can only find difference when we call die and croak within any
other function.
croak will gives information about the caller such as function name
and line number..etc.
die will give error and gives the line number where the error has occured.
It's not necessarily wrong to use die() but croak() gives you or your user a lot more information about what went wrong. There's also variables that can be set in the Carp namespace that can change this output to get more or less information.
It's equivalent to die() but with more information and control.
Still. This example may want to use croak if the connection parameters came directly from the inputs to the function as others pointed out.
If you write a test for yourself that triggers the exception then you will be your own client and appreciate which is better.
If it is very hard to test error condition it may be a case for die over croak. But any parameter validating errors should use croak.
The Carp routines are useful in your own modules because they act like die() or warn(), but with a message which is more likely to be useful to a user of your module.
https://perldoc.perl.org/Carp

Perl: catch error without die

I'm playing around with error handling and got a little problem.
I connect with a database using the DBI module.
I do my own error handling by using a subroutine that I call upon an error.
I can catch my own dies and handle them just fine but when my database connection fails, the DBI module apparently prints out it's own die :
DBI connect(...) failed: ORA-12154: TNS:could not resolve the
connect identifier specified (DBD ERROR: OCIServerAttach) at ...
How would I go about catching this ?
I tried using $SIG{__DIE__} like so :
local $SIG{__DIE__} = sub {
my $e = shift;
print "Error: " .$e;
};
This is on the bottom of my main file, in this file I also call the connect subroutine that is available in a module of my own. I also tried putting this piece of code on the bottom of my module but it still prints the error without the
Error:
in front of it.
DBI connect(...) failed: ORA-12154:
TNS:could not resolve the connect
identifier specified (DBD ERROR:
OCIServerAttach) at ...
How would I go about catching this ?
To catch and handle this level of error, use eval in block form, "eval { ... }". This will catch any die that happens in the sub code. If the code within an eval block dies, it will set $# and the block will return false. If the code does not die, $# will be set to ''.
Using signal handling via SIG{WARN} and SIG{DIE} is troublesome since they are global, there are also race conditions to consider (what happens if I get a signal while I'm handling a different signal? etc. The traditional issues of signal based computing). You're probably writing single-threaded code, so you're not worried about concurrency issues of multiple things calling die, but there is the user to consider (maybe he'll send a SIGKILL while you're trying to open the DBI connection)
In this specific case, you are using DBI. With DBI, you can control what happens in the case of error, if it should die, warn, or fail silently and wait for you to check the return status.
Here is a basic example of using eval { ... }.
my $dbh = eval { DBI->connect( #args) };
if ( $# )
{
#DBI->connect threw an error via die
if ($# =~ m/ORA-12154/i )
{
#handle this error, so I can clean up and continue
}
elsif ( $# =~ m/SOME \s* other \s* ERROR \s+ string/ix )
{
#I can't handle this error, but I can translate it
die "our internal error code #7";
}
else
{
die $#; #re-throw the die
}
}
There are some minor issues with using eval this way, having to do with the global scope of $#. The Try::Tiny cpan page has a great explanation. Try::Tiny handles a minimal Try/catch block setup and handles localizing $# and handling the other edge cases.
Okay, found the solution, apparently I needed __WARN__ instead of __DIE__ and this piece of code needed to be in the top of the file, before where the error was thrown, unlike the example I read stated :)
Include this in your SIG{__DIE__} block:
### Check if exceptions being caught.
return if $^S;
This will prevent your handler from being used on exception-based code that generates a die within an eval block.
There are lots of switches in DBI, like PrintError, RaiseError, etc. which you can adjust.
See http://search.cpan.org/perldoc?DBI
This is not as generic as an overall die catcher, but specifically for DBI error handling we actually have our own module providing wrappers around database calls; and one of the module's functionalities is to wrap eval (depending on a flag) around each DBI call.
This allows us to do custom error handling on data access level, such as query retries, statistics, automated failover and more - all transparent to the rest of the code.

What's broken about exceptions in Perl?

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