Table of Contents:
See Sometimes it Works Sometimes it does Not
To debug scripts running under mod_perl either use Apache::DB (interactive Perl debugging) or an older non-interactive method as described below.
NonStop
debugger option enables us to get some decent debug info when running under
mod_perl. For example, before starting the server:
% setenv PERL5OPT -d % setenv PERLDB_OPTS "NonStop=1 LineInfo=db.out AutoTrace=1 frame=2"
Now watch db.out for line:filename info. This is most useful for tracking
those core dumps that normally leave us guessing, even with a stack trace
from gdb. db.out will show you what Perl code triggered the core. 'man
perldebug' for more PERLDB_OPTS. Note, Perl will ignore PERL5OPT if PerlTaintCheck
is On
.
Perl ships with a very useful interactive debugger, however, it does not
run ``out-of-the-box'' in the Apache/mod_perl environment.
Apache::DB
makes a few adjustments so the two will cooperate.
To configure it use:
<Location /perl> PerlFixupHandler +Apache::DB SetHandler perl-script PerlHandler +Apache::Registry Options +ExecCGI </Location>
You must run the server in the single mode (with -X) to use
Apache::DB
.
When you run the script for the first time, you should let it run until it finishes. Starting from the second run you can run it as if it was a regular perl script.
Module and Scripts that were preloaded and compiled during the server startup will be not debuggable.
The filename and lines of Apache::Registry scripts are not displayed.
See the SUPPORT doc for hints on getting a stacktrace. To do this with
make test, build mod_perl giving Makefile.PL
the PERL_DEBUG=1
flag. Now execute
gdb ../apache_x.x.x/src/httpd (gdb) thttpd
(thttpd is defined in .gdbinit)
then, in another term run make run_tests, and at the gdb prompt:
(gdb) bt
To enable mod_perl debug tracing configure mod_perl with the PERL_TRACE option:
perl Makefile.PL PERL_TRACE=1
The trace levels can then be enabled via the MOD_PERL_TRACE
environment variable which can contain any combination of:
d - Trace directive handling during configuration read s - Trace processing of perl sections h - Trace Perl*Handler callbacks g - Trace global variable handling, interpreter construction, END blocks, etc. all - all of the above
add to httpd.conf:
PerlSetVar MOD_PERL_TRACE all
For example if you want to see a trace of the PerlRequire's and PerlModule's as they are loaded, use:
PerlSetVar MOD_PERL_TRACE d
As you know you need an unstriped executable to be able to debug it. While
you can compile the mod_perl with -g
(or PERL_DEBUG=1
) the apache install
strips the symbols.
Makefile.tmpl contains a line:
IFLAGS_PROGRAM = -m 755 -s
Removing the -s does the trick.
As I have mentioned it before, error_log
file is your best friend in CGI code debugging process.
While debugging my mod_perl and general CGI code, I keep my
error_log
file open in a dedicated terminal window (xterm), so I can see what
errors/warnings are being reported by server right away. I do it with:
tail -f /usr/local/apache/logs/error_log
which shows all the lines that are being added to the file.
If you cannot access your error_log
file because you are unable to telnet to your machine (generally a case
with some ISPs who provides user CGI support but no telnet access), you
might want to use a CGI script I wrote to fetch the latest lines from the
file (with a bonus of colored output for an easier reading). You might need
to ask your ISP to install this script for a general usage. See Watching the error_log file without telneting to the server.
Current perl implementation does not restore the original apache's C
handler when you use local $SIG{FOO}
clause. While save/restore of
$SIG{ALRM}
was fixed in the mod_perl 1.19_01 (CVS version), other signals are not yet
fixed. The real fix should probably be in Perl itself.
Untill recent local $SIG{ALRM}
restored the SIGALRM
handler to Perl's handler, not the handler it was in the first place
(apache's
alrm_handler()
). if you build mod_perl with PERL_TRACE=1
and set the MOD_PERL_TRACE
environment variable to g, you will see this in the error_log
file:
mod_perl: saving SIGALRM (14) handler 0x80b1ff0 mod_perl: restoring SIGALRM (14) handler from: 0x0 to: 0x80b1ff0
If nobody touched $SIG{ALRM}
, 0x0
would be the same address as the others.
If you work with signal handlers take a look at Sys::Signal
module, which solves the problem:
Sys::Signal
- Set signal handlers with restoration of existing C sighandler. Get it
from the CPAN.
The usage is simple, if the original code was:
eval { local $SIG{ALRM} = sub { die "timeout\n" }; alarm $timeout; ... db stuff ... alarm 0; }; die $@ if $@;
If a timeout happens and SIGALRM
is thrown, the alarm()
will be reset, otherwise alarm 0
is reached and timer is being reset as well.
Now you would write:
use Sys::Signal (); eval { my $h = Sys::Signal->set(ALRM => sub { die "timeout\n" }); alarm $timeout; ... do something thay may timeout ... alarm 0; }; die $@ if $@;
To see where an httpd is ``spinning'', try adding this to your script or a startup file:
use Carp (); $SIG{'USR1'} = sub { Carp::confess("caught SIGUSR1!"); };
Then issue the command line:
kill -USR1 <spinning_httpd_pid>
It is possible to profile code run under mod_perl with the
Devel::DProf
module available on CPAN. However, you must have apache version 1.3b3 or
higher and the PerlChildExitHandler
enabled. When the server is started, Devel::DProf
installs an
END
block to write the tmon.out
file, which will be run when the server is shutdown. Here's how to start
and stop a server with the profiler enabled:
% setenv PERL5OPT -d:DProf % httpd -X -d `pwd` & ... make some requests to the server here ... % kill `cat logs/httpd.pid` % unsetenv PERL5OPT % dprofpp
See also: Apache::DProf
(META: below are some snippets of strace outputs from list's emails)
[there was a talk about Streaming LWP through mod_perl and the topic was suggested optimal buffer size]
Optimal buffer size depends on your system configuration, watch apache with strace -p
(or truss
) when its sending a static file, here perlfunc.pod on my laptop (linux
2.2.7):
writev(4, [{"HTTP/1.1 200 OK\r\nDate: Wed, 02"..., 289}, {"=head1 NAME\n\nperlfunc - Perl b"..., 32768}], 2) = 33057 alarm(300) = 300 write(4, "m. In older versions of Perl, i"..., 32768) = 32768 alarm(300) = 300 write(4, "hout waiting for the user to hit"..., 32768) = 32768 alarm(300) = 300 write(4, ">&STDOUT") || die "Can't dup "..., 32768) = 32768 alarm(300) = 300 write(4, "LEHANDLE is supplied. This has "..., 32768) = 32768 alarm(300) = 300 write(4, "ite>,\nC<seek>, C<tell>, or C<eo"..., 25657) = 25657
Devel::Peek - A data debugging tool for the XS programmer
Let's see an example of Perl allocating buffer size only once, regardless
of my()
scoping, although it will realloc if the size is >
SvLEN:
use Devel::Peek; for (1..3) { foo(); } sub foo { my $sv; Dump $sv; $sv = 'x' x 100_000; $sv = ""; }
The output:
SV = NULL(0x0) at 0x8138008 REFCNT = 1 FLAGS = (PADBUSY,PADMY) SV = PV(0x80e5794) at 0x8138008 REFCNT = 1 FLAGS = (PADBUSY,PADMY) PV = 0x815f808 ""\0 CUR = 0 LEN = 100001 SV = PV(0x80e5794) at 0x8138008 REFCNT = 1 FLAGS = (PADBUSY,PADMY) PV = 0x815f808 ""\0 CUR = 0
We can see that on subsequent calls (after the first one) $sv
already has a preallocated memory.
so, if you can afford the memory, the larger the buffer means less
brk()
syscalls. if you watch that example with strace, you will only see calls to brk()
in the first time through the loop. So, this is a case where you module
might want to pre-allocate the buffer for example for LWP, a file scope
lexical, like so:
package Your::Proxy; my $buffer = ' ' x 100_000; $buffer = "";
This way, only the parent has to brk()
at server startup, each
child already will already have an allocated buffer, just reset to ``'',
when you are done.
|
||
Written by Stas Bekman.
Last Modified at 09/22/1999 |
![]() |
Use of the Camel for Perl is a trademark of O'Reilly & Associates, and is used by permission. |