Oct 302012
 
Article Perl

Sometimes we could have a perl script failing with an error message generated in an inner module. For instance:

Editing the Encode.pm module, we just find that in line 174 there is a call to the “decode” method.

But the Encode.pm module implements a generic functionality that is being used in many internal modules in our application. These modules are in turn called by other modules, etc. The result is that the error message does not provide enough information to help in debugging the error.

To solve this, we want to generate a stack trace. The stack trace is the sequence of calls to subroutines from the main program, through the intermediate modules, until the module where the error happens is reached.

Generating a stack trace with an eval{} block and Carp::cluck

To do this we edit the Encode.pm module, wrapping in an “eval{}” block the “decode” call where the error happens:

Whenever an error happens inside an eval block, the “$@” variable contains the error message. The call to the Carp::cluck method prints this error message, together with the stack trace.

When the script is executed again, the output is as follows:

Allthough it might seem a bit cryptic at first glance, in this error message we can see which subroutines where called, and the arguments they received, to reach the sentence where the error was triggered.

Reading it from bottom to top:

  • The main program (an apache web server using mod_perl) called the “handler” method in our request handler module Website::Handler::Base.
  • From this method, a call was made to the “run” method in Website::Handler::Results
  • The “run” method made a call to “print_html” in the same module
  • “print_html” made a call to “db_lookup” in the same module
  • “db_lookup” made a call to the “search_location” method in the Search::LocationSearch module
  • “seach_location” made a call to _UTF8_decode in the same module
  • Finally, the call to Encode was made and the error happened

We can even see that the argument passed to  _UTF8_decode is a text string ‘ guardarropa ĝirono’. In this string there is a non-ASCII character ‘ĝ’ that most likely is the reason for the error.

With all this information, we are in a much better position to debug the issue!

Generating an stack trace using exception capture

The method to generate the stack trace above has a drawback in that we had to edit the module where the error was being produced.

There is another possibility, by defining in the main program an exception handler that will be executed if the program dies unexpectedly

Let’s use as example a main program that calls a method in module A. this method, in turn, makes a call to another method in module B. In this last method, an arithmetic exception “division by zero” is generated.

In the main program, we add an exception handler for the signal __DIE__ by adding an entry in the special hashtable %SIG:

The module A.pm defines the method “subroutine_a”:

The module B.pm defines the method “subroutine_b”:

 

When this program is executed, the full stack trace of the error is printed:

Index of posts related to Perl programming

 Posted by at 10:16 am

 Leave a Reply

(required)

(required)