Buddy Burden > Debuggit-2.03 > Debuggit::Cookbook



Annotate this POD



New  2
Open  2
View/Report Bugs
Source   Latest Release: Debuggit-2.05


Debuggit::Cookbook - Debuggit example recipes


Herein are provided a number of (mostly) short examples on how to use Debuggit to do clever things. More examples from users are welcomed.

Adding to the debugging output ^

You can take advantage of the fact that the default formatter is stored as Debuggit::default_formatter to do some clever things.

Show timestamp

For instance, it's pretty trivial to add a timestamp to debugging output:

    # add timestamp to debugging (at least for this function/module/whatever)
    local $Debuggit::formatter = sub
        return scalar(localtime) . ': ' . Debuggit::default_formatter(@_);

Note how the local restricts the change in debuggit's behavior to the current scope.

Show caller info

Similar to the last recipe. This is only trickier because you have to figure out the right argument to caller.

    # all debugging statements in the current scope will show function name
    local $Debuggit::formatter = sub
        # note that caller(0) would be this formatter sub, and
        # caller(1) would be debuggit(), so caller(2) is what we want
        # element 3 is the subroutine name (which includes the package name)
        return (caller(2))[3] . ': ' . Debuggit::default_formatter(@_);

Note that this example only handles the simple cases--if your debuggit() calls get stuck inside eval's or coderef's or anything like that, this breaks down. But often the simple case is close enough.

Controlling where debugging goes ^

Output to a log file

Perhaps you want a log file:

    my $log = '/tmp/debug.log';
    $Debuggit::output = sub
        open(LOG, ">>$log") or return;
        print LOG @_;

Notice how you have to append to the file, else multiple debuggit calls will just overwrite each other.

Debug to a string

Instead of printing debugging immediately, perhaps you want to save them up and print them out at the end. This could be useful e.g. when debugging web pages.

    our $log_msg;
    local $Debuggit::output = sub { $log_msg .= join('', @_) };

Again, we're appending. We join all the args together (although most formatters will return only one value, probably best not to assume), but use no separator. This example uses our instead of my for the string; this way, the variable is accessible from outside the current scope, which might be necessary for later printing (depending on where the current scope is).

Interesting debugging functions ^

A separator function

Remember that functions don't have to take any arguments, or return any. For instance, you could replace this:

    debuggit('=' x 40);
    debuggit("new code section starts here");

with this:

    debuggit(SEPARATOR => "new code section starts here");

by defining your function thus:

    Debuggit::add_func(SEPARATOR => 0, sub
        $Debuggit::output->('=' x 40);
        return ();

Since we're replacing two calls with one, we use a call to $Debuggit::output to make sure that the separator line goes where it should, even if someone wants to change where that is. To make sure we don't insert an undef into the debugging output stream, we return an empty list.

Fun with policy modules ^

Test suite debugging

Although a policy module will typically pass a debug value through to Debuggit, it doesn't have to. For instance, if you're writing a module for all your test scripts to include, you might wish to force DEBUG to 1. That's easy:

    package MyTestDebuggit;

    use Debuggit ();
    use Test::More;

    $Debuggit::output = sub { diag @_ };        # nicer with Test::More et al

    sub import
        Debuggit->import(PolicyModule => 1, DEBUG => 1);

Putting it all together ^

This section contains slightly longer recipes showcasing multiple features of Debuggit.

Debugging when STDERR is redirected

Recently, I was trying to debug some CPAN modules that were failing in some of my test files. The CPAN modules were being called from a script, and the script was being called with its STDERR (and STDOUT, for that matter) redirected so it could be captured by the test script. This can make it pretty tough to debug, but I came up with a pretty quick solution based on Debuggit. I've extended it and tweaked it a bit since I originally wrote it; here's what it looks like today:

    package Debuggit::TermDirect;

    use Carp;
    use IO::Handle;
    use Method::Signatures;

    use Debuggit ();

    our $count = 0;


    $Debuggit::formatter = sub { return '#>>> ' . ++$count . '. ' . Debuggit::default_formatter(@_) };
    $Debuggit::output = sub { open_direct(); DIRECT->printflush(@_); };

    sub import
        my $class = shift;
        Debuggit->import(PolicyModule => 1, DEBUG => 1);

        Debuggit::add_func(CMD => 1, method ($cmd)
            my @lines = `$cmd`;
            chomp @lines;
            return @lines;

        Debuggit::add_func(ENV => 1, method ($varname)
            return ("\$$varname =", $ENV{$varname});

    sub open_direct
        if (tell(DIRECT) == -1)
            open(DIRECT, '>/dev/tty') or croak("couldn't open channel to terminal");

Let's look at a few of the features:

syntax highlighting: