Carp is certainly one way to do it. What you have to be aware of is that Carp uses a concept of "safe calls". Essentially it assumes that when one sub calls another sub in the same package, the author of the package knows what he/she is doing, and doesn't include this call in the stack trace. So the stack trace only shows places where the call stack crosses package boundaries.
Setting $Carp::Verbose to true switches off that behaviour, so stack traces will include all calls.
A better solution though, is to notice that Perl doesn't just only support die($string) as a way of throwing an exception. die can be called on any scalar value, including blessed objects. There are a number of modules on CPAN providing useful classes that can be used for throwing exceptions. Throwable::Error is one of the best ones, but has a dependency on Moose. Exception::Class::Base and Error::Base are also good.
Here's an example using Exception::Class::Base
use Exception::Class (
'My::Exception' => { description => 'simple exception'},
);
My::Exception->Trace(1); # enable catching full traces
eval {
My::Exception->throw('Foo');
};
if ($@)
{
my $e = $@;
$e->show_trace(1);
warn $e->as_string;
}
Exception::Class also offers some fairly nice syntactic sugar for exception catching...
use Exception::Class (
'My::Exception' => { description => 'simple exception'},
);
My::Exception->Trace(1); # enable catching full traces
eval {
My::Exception->throw('Foo');
};
if (my $e = Exception::Class->caught('My::Exception'))
{
$e->show_trace(1);
warn $e->as_string;
}
Overall, I'd say the gold standard of exceptions for Perl is Throwable::Error combined with either TryCatch or Try::Tiny. These introduce some pretty heavy dependencies, but if you can afford them, the combination can't be beaten for maintainable, readable exception handling. |