NAME

App::Trace - Embedded debug statements, including call/return tracing

SYNOPSIS

In a program (such as the following one named "foo"), you can do the following...

#!/usr/bin/perl

use App::Option;  # App::Trace was written to be used with App::Options
use App::Trace;   # enable tracing support

use Foo;
&run();
sub run {
    &App::sub_entry if ($App::trace);        # trace subroutine entry
    my $foo = Foo->new();
    $foo->run();
    &App::sub_exit() if ($App::trace);       # trace subroutine exit
}

in a module (i.e. Foo.pm), you can do the following...

package Foo;
# new(): a generic object constructor
sub new {
    &App::sub_entry if ($App::trace);        # trace method entry
    my ($this, @args) = @_;
    my $class = ref($this) || $this;
    my $self = { @args };
    bless $self, $class;
    &App::sub_exit($self) if ($App::trace);  # trace method exit
    return($self);
}
sub run {
    &App::sub_entry if ($App::trace);        # trace method entry
    print "Expression: (1 + 2) * (7 - (2*2))\n";
    my $value = $self->multiply(
        $self->add(1, 2),
        $self->subtract(7, $self->multiply(2, 2))
    );
    print "Value:      $value\n";
    &App::sub_exit() if ($App::trace);       # trace method exit
}
sub add {
    &App::sub_entry if ($App::trace);        # trace method entry
    my ($self, $operand1, $operand2) = @_;
    my $value = $operand1 + $operand2;
    &App::sub_exit($value) if ($App::trace); # trace method exit
    return($value);
}
sub subtract {
    &App::sub_entry if ($App::trace);        # trace method entry
    my ($self, $operand1, $operand2) = @_;
    my $value = $operand1 - $operand2;
    &App::sub_exit($value) if ($App::trace); # trace method exit
    return($value);
}
sub multiply {
    &App::sub_entry if ($App::trace);        # trace method entry
    my ($self, $operand1, $operand2) = @_;
    my $value = $operand1 * $operand2;
    &App::sub_exit($value) if ($App::trace); # trace method exit
    return($value);
}

Then when you invoke the program normally, you get no debug output.
You only get the expected program output.

  foo

However, when you invoke the program with something like the following...

  foo --trace

you get trace output like the following.

...

Try the following options...

  foo --trace --trace_width=0    # unlimited width (long lines wrap on screen)
  foo --trace --trace_width=78   # set max width of output
  foo --trace --trace_width=78 --trace_justify    # right-justify package
  foo --trace=main               # only trace subs in "main" package
  foo --trace=Foo                # only trace subs in "Foo" package
  foo --trace=Foo.multiply       # only trace the multiply() method in the Foo package
  foo --trace=main,Foo.run       # trace a combo of full packages and specific methods

DESCRIPTION

App::Trace provides debug/tracing support for perl programs and modules.

The basic concept is that you put a special call at the beginning and end of each subroutine/method, and when tracing is enabled, you can see the flow of your program.

This module reflects my dislike of the perl debugger. I also dislike putting in print statements to debug, then commenting them out when I'm done. I would rather put debug statements in my code and leave them there. That way, when programs work their way into production, they can still be debugged by using appropriate command line options.

Perl modules which are written to be used with App::Trace can be debugged easily without entering the perl debugger. The output of tracing is a "program trace" which shows the entry and exit of every subroutine/method (and the arguments). This trace is printed in a format which allows you to follow the flow of the program.

Someday I might figure out how to do this at a language level so it will work on any module, not just ones which have been specially instrumented with &App::sub_entry() and &App::sub_exit() calls. In fact, I started work on this with the Aspect.pm module, but that was specific to perl version 5.6.x and didn't work with 5.8.x. That's when I decided I would write App::Trace which would work on any Perl (even back to 5.5.3, which I consider to be the first Perl 5 to support for deep backward compatibility).

The App-Trace distribution began life as a collection of routines pulled out of the App-Context distribution. I created App-Trace because these routines were very useful independent of the rest of the framework provided by App-Context.

App::Trace is dependent on App::Options. It is possible to use App::Trace without App::Options, but they share a common convention with regard to certain global variables in the "App" package/namespace.

It is expected that when App::Trace is mature, the routines included will be removed from App.pm module in the App-Context distribution. The App-Context distribution will then be dependent on App::Trace for these features.

Attributes, Constants, Global Variables, Class Variables

Global Variables

* Global Variable: %App::scope              scope for debug or tracing output
* Global Variable: $App::scope_exclusive    flag saying that the scope is exclusive (a list of things *not* to debug/trace)
* Global Variable: %App::trace              trace level
* Global Variable: $App::DEBUG              debug level
* Global Variable: $App::DEBUG_FILE         file for debug output

sub_entry()

* Signature: &App::sub_entry;
* Signature: &App::sub_entry(@args);
* Param:     @args        any
* Return:    void
* Throws:    none
* Since:     0.01

This is called at the beginning of a subroutine or method (even before $self may be shifted off).

sub_exit()

* Signature: &App::sub_exit(@return);
* Param:     @return      any
* Return:    void
* Throws:    none
* Since:     0.01

This subroutine is called just before you return from a subroutine or method.

in_debug_scope()

* Signature: &App::in_debug_scope
* Signature: App->in_debug_scope
* Param:     <no arg list supplied>
* Return:    void
* Throws:    none
* Since:     0.01

This is called within a subroutine or method in order to see if debug output should be produced.

if ($App::debug && &App::in_debug_scope) {
    print "This is debug output\n";
}

Note: The App::in_debug_scope subroutine also checks $App::debug, but checking it in your code allows you to skip the subroutine call if you are not debugging.

if (&App::in_debug_scope) {
    print "This is debug output\n";
}

debug_indent()

* Signature: &App::debug_indent()
* Signature: App->debug_indent()
* Param:     void
* Return:    $indent_str     string
* Throws:    none
* Since:     0.01

This subroutine returns the $indent_str string which should be printed before all debug lines if you wish to line the debug output up with the nested/indented trace output.

ACKNOWLEDGEMENTS

* Author:  Stephen Adkins <spadkins@gmail.com>
* License: This is free software. It is licensed under the same terms as Perl itself.

SEE ALSO