We’ve all been there: Deep in the bowels of a program, trying to figure out why something’s not working right.
Maybe a variable isn’t getting the right value. Maybe a function or method isn’t getting called or has the wrong arguments. Maybe we don’t even know if a line of code is being reached.
So what do we do? We litter our code with print
statements or logging. “Got value.” “Calling foo
with x
.” “Reached line 42.”
And then we have to make sure to clean it all out , lest these informal clues make their way to production and the eyes of users.
There’s a better way
What if I told you that you could freeze time in the middle of your program and examine all these details while they happen, or even before they happen? That you could be alerted when variables or expressions changed and immediately dive in to see the cause? That you could even run exploratory test code and play “what if” scenarios?
All of this is possible with a debugger, and Perl has one built-in. Run your program with perl -d
, and after a slight delay you’re presented with a new command line prompt:
% perl -d hello.pl
Loading DB routines from perl5db.pl version 1.57
Editor support available.
Enter h or 'h h' for help, or 'man perldebug' for more help.
main::(hello.pl:7): say 'Hello world!';
DB<1>
Before you go any further, you might want to know how to exit the debugger. Just type q
and then press Enter and you’ll be back at your normal command line.
Perl also comes with a good (if incomplete) tutorial on using the debugger, and I suggest you work through that to familiarize yourself. It will tell you how to get help, list and view variables and lines of code, set breakpoints, and step through line by line.
And then there’s the full manual, where you can learn how to do things like getting a stack backtrace of all calls leading up to the current line.
My favorite debugging trick
By far my favorite thing to do with the debugger is to run it against test scripts using the prove
command. This takes advantage of prove
’s ability to run an arbitrary interpreter through its test harness. Run it like this:
% prove --verbose --lib --exec 'perl -Ilib -d' t/foo.t
…and you’ll be able to step through the test script at t/foo.t
, loading any necessary modules from the lib
directory, getting verbose test output along the way.
This is extremely helpful when paired with modules like Test::Mojo, which can load Mojolicious web application classes and then exercise them using its own user agent. (You can do similar things with other PSGI applications using Plack::Test.)
A caveat
If you’re debugging and testing your applications strictly through network requests to another process, such as through Test::WWW::Mechanize, running the debugger will only show you the client-side of things and not allow you to step through execution of the server side. This is especially prevalent among legacy apps not using the PSGI protocol. If you’re using Apache mod_perl have a look at Apache::DB, which enables you to run the Apache httpd
web server with the interactive debugger.
So what’s your superpower?
A debugger is a common feature in many languages and development environments, and Perl has had one for decades. Yet I’m constantly surprised that more developers don’t know about or don’t use this powerful tool that can cut through the “add print
s/run/stop/add more print
s/run” cycle.
How can you integrate the Perl debugger into your programming workflow? Leave me a message in the comments and let me know.
Top comments (3)
I've modified mine to use
Data::Printer
for dumping output from thex
command, and show several lines of context while debugging. I also have it skip over several modules (such as Moose) whose internals I don't want to wade through while debugging.More about debugging: youtube.com/watch?v=AyyFQJjk7Lw
Perl Debugger is useful, but not very popular, so it's nice to see an introduction.