Let's say I have a module Bar that is a subclass wrapper for module Foo. I want calls to Bar's methods to mimic Foo's exactly -- even down to fatal errors. So far, easy enough; I just call the SUPER method.
sub stuff {
# Do stuff here
SUPER::stuff(@_);
# Do more stuff here
}
But, let's say that I want to catch, log, and rethrow any fatal errors SUPER::stuff()
produces. First two steps are easy:
sub stuff {
# Do stuff here
eval {
SUPER::stuff(@_);
};
$@ and log("Naughty, naughty: $@");
# Do more stuff here
}
... but I don't know how to do the last part. How do I re-throw the error in such a way that the caller will be unable to distinguish between a call to Foo->stuff()
and a call to Bar->stuff()
? Can I just insert die $@
after the log statement and expect it to do what I want, or are there nuances here that would likely get me into trouble?
The full code to safely eval/catch/log/rethrow in Perl can be a bit verbose.
sub stuff {
# Do stuff here
local $@; # don't reset $@ for our caller.
my $eval_ok = eval { # get the return from eval, it will be undef if the eval catches an error.
SUPER::stuff(@_);
1; # return 1 (true) if there are no errors caught.
};
if (!$eval_ok) { # don't trust $@ it might have been reset as the eval unrolled.
my $error = $@ || 'unknown error'; # copy $@ incase write_log resets $@, or is later changed to cause it to reset $@.
write_log("Naughty, naughty: $error");
die $error; # after all that we can rethrow our error.
}
# Do more stuff here
}
You can use Try::Tiny sugested by mob to simplify:
sub stuff {
# Do stuff here
try {
SUPER::stuff(@_);
} catch {
my $error = $_;
write_log("Naughty, naughty: $error");
die $error;
}
# Do more stuff here
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With