I have a few older scripts which do minimal logging and instead report errors to STDERR via die/warn. Recently, there was an increased need to log/track all die and warn
messages. For this, I wrote a single warn/die hook
mechanism whereby I can now set my own handlers
that will get invoked on any warn/die call. This is handy as I can also do any amount of logging/tracking inside those handlers, without having to worry about changing the original code around too much.
Although this new code worked fine, it yet didn't behave quite as I expected it to...
While I figured out how to skip my handler routine
when die/warn is called inside an eval block, I still
have this one issue with my die handler (SIG{__DIE__})
being reset after an eval block.
If you uncomment the first die just before the eval block,
the handler will get executed fine.
Here's the output I get:
Warn before init! at die_replace.pl line 4.
WARNING: Warned at die_replace.pl line 8.
(Check logs for more info)
-----
ERROR: Died at die_replace.pl line 11.
(Check logs for more info)
-----
However, doing the same thing just after the eval block doesn't
seem to also invoke the handler. The output that I get
is this:
Warn before init! at die_replace.pl line 4.
WARNING: Warned at die_replace.pl line 8.
(Check logs for more info)
-----
Caught: died inside eval!
Died for real! at die_replace.pl line 29.
I'm wondering what is
there (somewhere within the eval block) that causes
SIG{__DIE__} to be reset? Or is there any other bug
that I'm not noticing?
Here's the code:
use strict;
warn "Warn before init!";
init();
warn "Warned";
# This die would invoke my SIG{__DIE__} handler
# die "Died";
eval {
#
# Due to an implementation glitch in perl,
# $SIG{__DIE__} would still get invoked even
# if I'm inside an eval! Luckily $^S will be
# set to true in this case.
#
die "died inside eval!\n";
};
if ($@) {
print "Caught: $@\n";
}
# For some reason, _this_ die would not invoke
# my SIG{__DIE__} handler (die_handler).
# Where did SIG{__DIE__} got reset/cleared?
die "Died for real!";
print "done\n";
################################
# SUBS
#
################################
# HANDLERS
sub die_handler {
# Use this in order not to run this handler
# if die was called inside an 'eval'
# (see the section on "$^S" in the perlvar manpage)
# $^S is true if inside an eval, otherwise false.
die @_ if $^S;
# log error
# $Log->write($UGLI::UGLI_ERR, $_[0]);
# complain...
print "ERROR: $_[0]\n (Check logs for more info)\n-----\n\n";
exit(1);
}
sub warn_handler {
# log warning
# $Log->write($UGLI::UGLI_WARN, $_[0]);
# complain...
print "WARNING: $_[0]\n (Check logs for more info)\n-----\n\n";
# return false if we also wish to execute
# original warn handler.
return 1;
}
sub init {
init_handler(
name => "__DIE__",
handler => \&die_handler
);
init_handler(
name => "__WARN__",
handler => \&warn_handler
);
}
sub init_handler {
my (%args) = @_;
my $sig_name = $args{name};
my $new_handler = $args{handler};
my $old_sig = $SIG{$sig_name} || sub {};
$SIG{$sig_name} = sub {
$new_handler->(@_) ||
$old_sig->(@_);
}
}
"There is no system but GNU, and Linux is one of its kernels." -- Confession of Faith
|
Edit kudra,
2002-04-16
Added readmore