Learning to use the httpd error log to debug CGI programs
A typical idiom in Perl might be:
open(FILE, "$filename") ||
die "Cannot open $filename";
The above line means that $filename should be opened for reading, and that the opened file should be accessed via the descriptor named FILE. If the program cannot open the file for some reason the program should terminate, producing a message. Let's look at how that works within a CGI program:
#!/usr/local/bin/perl5 -w
use strict; # Check our syntax strictly
use diagnostics; # Tell us how to fix mistakes
use CGI; # Import the CGI module
# Create an instance of CGI
my $query = new CGI;
# Set this to a file
my $filename = "/foo/bar/blah.txt";
# Send the MIME header
print $query->header("text/html");
# Begin the HTML
print $query->start_html(-title =>
"Hello, world!");
# Print the contents of $filename
open (FILE, "$filename") ||
die "Cannot open $filename ";
print while (<FILE>);
close (FILE);
# End the HTML
print $query->end_html();
Looks good, right? Well, the above will indeed work just fine,
assuming that $filename exists. But if and when
it doesn't, or if the program doesn't have permission to read the
file, the second half of the statement is executed—and the program
terminates, producing an error message.
If $filename doesn't exist, and you run the program from the command line, you get the following output:
Content-type: text/html <HTML><HEAD><TITLE>Hello, world!</TITLE> </HEAD><BODY>Uncaught exception from user code: Cannot open /tmp/blah.txt at ./test-8.pl line 20.
But if you run it from your web browser, you get nothing at all—no error message, and no response, because the error message “Cannot open /tmp/blah.txt” was sent to stderr, rather than stdout. The error log, however, contains the following:
Uncaught exception from user code: Cannot open /tmp/blah.txt at /home/reuven/Text/Websmith/test-8.pl line 20.Note that the error message is inserted into the log without date or time information, since the text was sent directly by the Perl program (or by the Perl binary), rather than the web server. The web server automatically stamps its own error messages with the current time and date, but your programs don't enjoy that feature—unless, of course, you include the Carp library included with CGI.pm, which redefines the die routine, as well as several others, such that error messages are preceded by the relevant time and date. Thus, if you include the line:
use CGI::Carp;at the top of the above program, the program still fails as expected, but your error log now contains the following entry:
[Tue Dec 3 11:55:14 1996] test-8.pl: Cannot open /tmp/blah.txt at /home/reuven/Text/Websmith/test-8.pl line 21.Now we know not only what went wrong, but also when it happened. The Carp library can be very useful when debugging CGI programs, especially if you find yourself running the same program repeatedly. This way, there isn't any question whether the error occurred the first or fifth time that you ran the program, since the time at which the program ran is written right next to the error message.
Once you have installed Carp, you can use it for recording non-fatal errors, as well. For example, if you are trying to keep track of the value of a particular variable, you can include the line:
carp 'variablename = "'. $variablename . '"';
Because it includes the time and date information, this is better than:
print STDERR 'variablename = "', $variablename,
'"';
Although using Perl's built-in syntax checkers and warnings (with
the -w flag and the
strict and
diagnostics modules) is a great
idea, realize that loading the CGI::Carp module
will set off warning bells because it redefines several
subroutines. You can ignore these warnings, but don't be surprised
when they appear.
All this time, we have ignored our users, who are really supposed to be the focus of our efforts. It's all well and good that we are improving error messages for the purpose of debugging programs, but none of the ideas that we have looked at until now have done much for what the user sees.
The problem is that if you use die to output a message to the error log, the program dies off before it has a chance to produce any sort of “whoops” message for the user. If you're building an interactive web site, the last thing you want to do is present a user with a blank results page; at the very least, you should tell him that something has gone wrong, and that you are trying to fix the problem.
One easy way to do this is to replace the line:
open (FILE, "$filename") ||
die "Cannot open $filename ";
with the following:
open (FILE, "$filename") ||
&log_and_die ("Cannot open $filename ");
This new version opens the file as necessary, but invokes a
subroutine named log_and_die, if the file cannot
be opened. You can then define the subroutine as follows:
sub log_and_die
{
# Get arguments
my $string = shift;
# Begin the HTML
print $query->start_html(-title => "Error");
# Give a message
print "<P>Sorry, but this program ";
print "has encountered an error. The system ";
print "administrator has been ";
print "informed.</P>\n";
print "<P>Would you like to return to the;
print "<a href=\"/\">home page</a>?\n";
# End the HTML
print $query->end_html();
# Now die with the error message
die $string;
}
The above routine is obviously a bit Spartan for most tastes, but
the point is obvious: By wrapping errors into a separate routine,
you can have our cake and eat it, too. The user gets an error
message directing him or her to another site, and apologizing
profusely for the program's errors. And the system administrator or
web master gets a note in the error log describing exactly what
went wrong, making it possible to fix the program more easily.
You could obviously add to this routine. For starters, a good idea might be to e-mail the system administrator or programmer to let him or her know that an error had occurred. If the program were part of a critical system, then perhaps it would even be a good idea to send e-mail to a system tied into an alphanumeric paging system.
Realizing the promise of Apache® Hadoop® requires the effective deployment of compute, memory, storage and networking to achieve optimal results. With its flexibility and multitude of options, it is easy to over or under provision the server infrastructure, resulting in poor performance and high TCO. Join us for an in depth, technical discussion with industry experts from leading Hadoop and server companies who will provide insights into the key considerations for designing and deploying an optimal Hadoop cluster.
Sponsored by AMD
Built-in forensics, incident response, and security with Red Hat Enterprise Linux 6
Every security policy provides guidance and requirements for ensuring adequate protection of information and data, as well as high-level technical and administrative security requirements for a system in a given environment. Traditionally, providing security for a system focuses on the confidentiality of the information on it. However, protecting the data integrity and system and data availability is just as important. For example, when processing United States intelligence information, there are three attributes that require protection: confidentiality, integrity, and availability.
Learn more about catching the bad guy in this free white paper.
Sponsored by DLT Solutions
Free Webinar: Hadoop
How to Build an Optimal Hadoop Cluster to Store and Maintain Unlimited Amounts of Data Using Microservers
Realizing the promise of Apache® Hadoop® requires the effective deployment of compute, memory, storage and networking to achieve optimal results. With its flexibility and multitude of options, it is easy to over or under provision the server infrastructure, resulting in poor performance and high TCO. Join us for an in depth, technical discussion with industry experts from leading Hadoop and server companies who will provide insights into the key considerations for designing and deploying an optimal Hadoop cluster.
Some of key questions to be discussed are:
- What is the “typical” Hadoop cluster and what should be installed on the different machine types?
- Why should you consider the typical workload patterns when making your hardware decisions?
- Are all microservers created equal for Hadoop deployments?
- How do I plan for expansion if I require more compute, memory, storage or networking?
| Designing Electronics with Linux | May 22, 2013 |
| Dynamic DNS—an Object Lesson in Problem Solving | May 21, 2013 |
| Using Salt Stack and Vagrant for Drupal Development | May 20, 2013 |
| Making Linux and Android Get Along (It's Not as Hard as It Sounds) | May 16, 2013 |
| Drupal Is a Framework: Why Everyone Needs to Understand This | May 15, 2013 |
| Home, My Backup Data Center | May 13, 2013 |
- RSS Feeds
- Dynamic DNS—an Object Lesson in Problem Solving
- Making Linux and Android Get Along (It's Not as Hard as It Sounds)
- Using Salt Stack and Vagrant for Drupal Development
- New Products
- A Topic for Discussion - Open Source Feature-Richness?
- Drupal Is a Framework: Why Everyone Needs to Understand This
- Validate an E-Mail Address with PHP, the Right Way
- What's the tweeting protocol?
- Tech Tip: Really Simple HTTP Server with Python




1 hour 6 min ago
5 hours 33 min ago
9 hours 8 min ago
9 hours 41 min ago
12 hours 4 min ago
12 hours 8 min ago
12 hours 9 min ago
16 hours 34 min ago
18 hours 25 min ago
23 hours 38 min ago