Perl Programming Page 3 - Debugging Perl |
I can change the warn and die functions myself by messing with %SIG. I like to use these to peer into code I’m trying to figure out, but I don’t use these to add features to code. It’s just part of my debugging toolbox. The pseudokeys __WARN__ and __DIE__ hold the functions that perform those actions when I use the warn or die functions. I can use a reference to a named subroutine or an anonymous subroutine: $SIG{__DIE__} = \&my_die_handler; Without going through the entire code base, I can change all of the die calls into the more informative croak calls.§ In this example, I preface the subroutine call with an & and no parentheses to trigger Perl’s feature to pass on the current argument list to the next subroutine call so croak gets all of the arguments I pass: use Carp; die "I'm going now!"; # really calls croak now If I only want to do this for part of the code, I can use local (since %SIG is a special variable always in main::). My redefinition stays in effect until the end of the scope: local $SIG{__DIE__} = sub { &Carp::croak }; After either of my customized routines runs, the functions do what they would otherwise do; warn lets the program continue, and die continues its exception processing and eventually stops the program.‖ Since croak reports each level of the call stack and I called it from an anonymous subroutine, I get an artifact in my output: use Carp; print "Starting program...\n"; $SIG{__DIE__} = sub { &Carp::croak; foo(); # program dies here sub foo { bar() } sub bar { die "Dying from bar!\n"; } In the stack trace, I see a subroutine call from __ANON__ followed by the subroutine calls I expect to bar() and foo(): Starting program... I change my anonymous subroutine to adjust the position in the stack where croak starts its report. I set the value of $Carp::CarpLevel to the number of levels I want to skip, in this case just 1: $SIG{__DIE__} = sub { &Carp::croak; Now I don’t see the unwanted output: Starting program... For a real-life example of this in action, check out the CGI::Carp module. Lincoln Stein uses the %SIG tricks to redefine warn and die in a web-friendly way. Instead of an annoying “Server Error 500” message, I can get useful error output by simply loading the module. While loading, CGI::Carp sets $SIG{__WARN__} and $SIG{__DIE__}: use CGI::Carp qw(fatalsToBrowser); The fatalsToBrowser function takes over the resulting page to show me the error, but the module has other interesting functions such as set_message, which can catch compile-time errors and warningsToBrowser, which makes the warnings in HTML comments embedded in the output. Of course, I don’t recommend that you use this in production code. I don’t want users to see the program’s errors. They can be handy when I have to debug a program on a remote server, but once I figure out the problem, I don’t need it anymore. By leaving it in there I let the public figure out how I’m doing things, and that’s bad for security.
blog comments powered by Disqus |
|
|
|
|
|
|
|