The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.

NAME

Devel::DumpTrace - Evaluate and print out each line before it is executed.

VERSION

0.29

SYNOPSIS

    perl -d:DumpTrace program.pl
    perl -d:DumpTrace=verbose program.pl
    perl -d:DumpTrace=quiet program.pl
    perl -d:DumpTrace=<n> program.pl

    perl -d:DumpTrace::PPI program.pl
    perl -d:DumpTrace::noPPI program.pl

DESCRIPTION

Similar to Devel::Trace, this module will cause a message to be printed to standard error for each line of source code that is executed. In addition, this module will attempt to identify variable names in the source code and substitute the values of those variables. In this way you can see the path of execution through your program as well as the value of variables at each step of the program.

For example, if your program looks like this:

    #!/usr/bin/perl
    # a demonstration of Devel::DumpTrace
    $a = 1;
    $b = 3;
    $c = 2 * $a + 7 * $b;
    @d = ($a, $b, $c + $b);

then the DumpTrace output will look like:

    $ perl -d:DumpTrace demo.pl
    >>>>> demo.pl:3:        $a:1 = 1;
    >>>>> demo.pl:4:        $b:3 = 3;
    >>>>> demo.pl:5:        $c:23 = 2 * $a:1 + 7 * $b:3;
    >>>>> demo.pl:6:        @d:(1,3,26) = ($a:1, $b:3, $c:23 + $b:3);

There are also more verbose modes which will produce even more detailed output:

    $ perl -d:DumpTrace=verbose demo.pl
    >>  demo.pl:3:
    >>>              $a = 1;
    >>>>>            1 = 1;
    -------------------------------------------
    >>  demo.pl:4:
    >>>              $b = 3;
    >>>>>            3 = 3;
    -------------------------------------------
    >>  demo.pl:5:
    >>>              $c = 2 * $a + 7 * $b;
    >>>>             $c = 2 * 1 + 7 * 3;
    >>>>>            23 = 2 * 1 + 7 * 3;
    -------------------------------------------
    >>  demo.pl:6:
    >>>              @d = ($a, $b, $c + $b);
    >>>>             @d = (1, 3, 23 + 3);
    >>>>>            (1,3,26) = (1, 3, 23 + 3);
    -------------------------------------------

See $Devel::DumpTrace::TRACE under the "VARIABLES" section for more details about the different levels of verbosity.

This distribution comes with both a basic parser and a PPI-based parser (which relies on PPI to understand your source code). The PPI version has more features and fewer limitations than the basic parser. If the PPI module is installed on your system, then this module will automatically use the PPI-based parser to analyze the traced code. You can force this module to use the basic parser by running with the -d:DumpTrace::noPPI argument or by setting the DUMPTRACE_NOPPI environment variable:

    # use PPI if available, otherwise use basic parser
    $ perl -d:DumpTrace program.pl

    # use PPI, fail if it is not available
    $ perl -d:DumpTrace::PPI program.pl

    # always uses basic parser
    $ perl -d:DumpTrace::noPPI program.pl
    $ DUMPTRACE_NOPPI=1 perl -d:DumpTrace program.pl

See the "BUGS AND LIMITATIONS" section for important, er, limitations of this module, especially for the basic parser.

SUBROUTINES/METHODS

None of interest.

VARIABLES

$TRACE

$Devel::DumpTrace::TRACE

Controls whether and how much output is produced by this module. Setting $Devel::DumpTrace::TRACE to zero will disable the module. Since this module can produce a lot of output and has other overhead that can considerably slow down your program (by a factor of 50 or more), you may find it useful to toggle this variable for critical sections of your code rather than leave it set for the entire program. For example:

    BEGIN { $Devel::DumpTrace::TRACE = 0 }

    &some_non_critical_code_that_more_or_less_works();

    $Devel::DumpTrace::TRACE = 'normal';
    &the_critial_code_you_want_to_debug();
    $Devel::DumpTrace::TRACE = 0;

    &some_more_non_critical_code();

or to enable tracing in a local block:

    {
        local $Devel::DumpTrace::TRACE = 1;
        &the_critical_code;
    }

In general higher values of $Devel::DumpTrace::TRACE will cause more output to be produced. Let's consider this simple program to see how the different $Devel::DumpTrace::TRACE settings affect the output:

    @a = (1 .. 40);
    $b = $a[4];
$Devel::DumpTrace::TRACE == 1

is the quietest mode. One line of output for each statement evaluated. The name of each variable in the source code and its value are included in the same line of output. Values of long scalars, long arrays, or long hash tables are heavily abbreviated:

    $ perl -d:DumpTrace=1 littledemo.pl
    >>>>> littledemo.pl:1:[__top__]:  @a:(1,2,3,4,5,6,...,40) = (1 .. 40);
    >>>>> littledemo.pl:2:[__top__]:  $b:5 = $a:(1,2,3,4,5,6,...,40)[4];
$Devel::DumpTrace::TRACE == 2

uses a single line of output for each statement evaluated. The name of each variable in the source code and its source code are included in the same line of output. Values of long scalar, arrays, and hashes are less heavily abbreviated.

    $ perl -I. -d:DumpTrace=2 littledemo.pl
    >>>>> littledemo.pl:1:[__top__]:  @a:(1,2,3,4,5,6,7,8,9,10,11,12,13,14, \
        15,16,17,18,19,20,21,22,23,24,25,26,27,...,40) = (1 .. 40);
    >>>>> littledemo.pl:2:[__top__]:  $b:5 = $a:(1,2,3,4,5,6,7,8,9,10,11,12, \
        13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,...,40)[4];
$Devel::DumpTrace::TRACE == 3

produces one line of output for each statement evaluated. The name of each variable in the source code and its source code are included in the same line of output. Values of long scalar, arrays, and hashes are not abbreviated at all. This is the default setting for the module.

    $ perl -I. -d:DumpTrace=3 littledemo.pl
    >>>>> littledemo.pl:1:[__top__]:  @a:(1,2,3,4,5,6,7,8,9,10,11,12,13,14, \
       15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37, \
       38,39,40) = (1 .. 40);
    >>>>> littledemo.pl:2:[__top__]:  $b:5 = $a:(1,2,3,4,5,6,7,8,9,10,11,12, \
       13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35, \
       36,37,38,39,40)[4];
$Devel::DumpTrace::TRACE == 4

produces up to four lines of output for each statement evaluated:

  • the source (file and line number) of the statement being evaluated

  • the origianl source code for the statement being evaluated

  • a valuation of the code before the statement has been evaluated by the Perl interpreter.

  • a valuation of the code after the statement has been evaluated by the Perl interpreter

A separator line will also be displayed between statements. Long scalar, arrays, and hashes may be abbreviated. Example output:

    $ perl -d:DumpTrace=4 littledemo.pl
    >>  littledemo.pl:1:[__top__]:
    >>>              @a = (1 .. 40);
    >>>>>            (1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20, \
        21,22,23,24,25,26,27,...,40) = (1 .. 40);
    -------------------------------------------
    >>  littledemo.pl:2:[__top__]:
    >>>              $b = $a[4] + $a[5];
    >>>>             $b = (1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19, \
        20,21,22,23,24,25,26,27,...,40)[4];
    >>>>>            5 = (1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19, \
        20,21,22,23,24,25,26,27,...,40)[4];
    -------------------------------------------
$Devel::DumpTrace::TRACE == 5

Like $TRACE 4, but long scalars, arrays, and hashes are not abbreviated.

    $ perl -I. -d:DumpTrace=5 littledemo.pl
    >>  littledemo.pl:1:[__top__]:
    >>>              @a = (1 .. 40);
    >>>>>            (1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21, \
        22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40) = (1 .. 40);
    -------------------------------------------
    >>  littledemo.pl:2:[__top__]:
    >>>              $b = $a[4] + $a[5];
    >>>>             $b = (1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19, \
        20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40)[4];
    >>>>>            5 = (1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19, \
        20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40)[4];

As these demos suggest, you can pass the $TRACE variable through the command line using the syntax -d:DumpTrace=level. In place of a number, you may also use the keywords quiet or verbose which will set the $TRACE variable to 1 and 5, respectively.

By default Devel::DumpTrace does not evaluate statements in any "system" modules, which are defined as any module from a file that resides under an absolute path in your system's @INC list of directories. If the $TRACE variable is set to a value larger than 100, then this module will drill down into such modules. See also "%EXCLUDE_PKG" and "%INCLUDE_PKG" for another way to exercise control over what packages this module will explore.

For convenience, the $Devel::DumpTrace::TRACE variable is aliased to the $Devel::Trace::TRACE variable. This way you can enable settings in your program that can be used by both Devel::Trace and Devel::DumpTrace.

$DUMPTRACE_FH

$Devel::DumpTrace::DUMPTRACE_FH

By default, all output from the Devel::DumpTrace module is written to standard error. This behavior can be changed by setting $Devel::DumpTrace::DUMPTRACE_FH to the desired I/O handle:

    BEGIN {
       # if Devel::DumpTrace is loaded, direct output to trace.txt
       if ($INC{'Devel/DumpTrace.pm'}) {
          open $Devel::DumpTrace::DUMPTRACE_FH, '>', '/path/trace.txt';
       }
    }

The output stream for the Devel::DumpTrace module can also be controlled with the environment variable DUMPTRACE_FH. If this variable is set to STDOUT, then output will be directed to standard output. If this variable contains another value that looks like a filename, this module will open a file with that name and write the trace output to that file.

Backwards-incompatible change: in v0.06, this variable was called XTRACE_FH.

$ARRAY_ELEM_SEPARATOR

$HASH_ENTRY_SEPARATOR

$HASH_PAIR_SEPARATOR

$Devel::DumpTrace::ARRAY_ELEM_SEPARATOR = ','

$Devel::DumpTrace::HASH_ENTRY_SEPARATOR = ';'

$Devel::DumpTrace::HASH_PAIR_SEPARATOR = '=>'

The Devel::DumpTrace module uses the preceding default values as delimiters when creating string representations of arrays, hashes, and array/hash references. If you wish to use different delimiters for whatever reason (maybe your arrays have a lot of elements with commas in them), you can change these values.

$XEVAL_SEPARATOR

$Devel::DumpTrace::XEVAL_SEPARATOR = ':'

In normal (non-verbose) mode, Devel::DumpTrace will display this token between the name of a variable and its value (e.g., $c:23). The default token is a colon (:), but you may change it by changing the value of the variable $Devel::DumpTrace::XEVAL_SEPARATOR.

%EXCLUDE_PKG

%INCLUDE_PKG

%Devel::DumpTrace::EXCLUDE_PKG, %Devel::DumpTrace::INCLUDE_PKG

Sets of packages that this module will never/always explore. These settings take precedence over the setting of the $Devel::DumpTrace::TRACE variable, and the settings of %Devel::DumpTrace::INCLUDE_PKG take precendence over the settings of %Devel::DumpTrace::EXCLUDE_PKG (that is, a package that is specified in both %EXCLUDE_PKG and %INCLUDE_PKG will be included).

@EXCLUDE_PATTERN

@INCLUDE_PATTERN

@Devel::DumpTrace::EXCLUDE_PATTERN, @Devel::DumpTrace::INCLUDE_PATTERN

List of regular expressions representing the packages that this module will never/always trace through.

Patterns can be from the command line or at module import time by passing arguments that begin with + to include packages or - to exclude packages:

    # always trace through  Foo::xxx  packages
    perl -d:DumpTrace=+Foo::.* my_script.pl

    # trace through Foo::Bar but not through Foo::Baz
    perl -d:DumpTrace=+Foo::Bar,-Bar::Foo my_script.pl

Any pattern from user input will be implicitly anchored (bracketed by ^ and $), so you must explicitly include wildcards to match a general pattern of package names.

    # don't trace any package containing /Foo/ except for Xyz::Foo
    perl -d:DumpTrace=-.*Foo.*,+Xyz::Foo my_script.pl

Settings in @INCLUDE_PATTERN take precendence over @EXCLUDE_PATTERN, so a package that matches a pattern in @INCLUDE_PATTERN will always be traced, even if it also matches one or more patterns in @EXCLUDE_PATTERN.

    # -Foo::Bar is ignored, because Foo::Bar also matches included .*::Bar
    perl -d:DumpTrace=-Foo::Bar,+.*::Bar my_script.pl

CONFIGURATION AND ENVIRONMENT

Devel::DumpTrace uses the DUMPTRACE_FH and DUMPTRACE_LEVEL environment variables to configure some package variables. See "VARIABLES". For Perl v5.8.8, which has a bug when the -d switch is used like perl -d:Foo=xxx ..., supplying the DUMPTRACE_LEVEL environment variable is a workaround to this bug.

The DUMPTRACE_NOPPI variable can be set to force this module to use the basic code parser and to ignore the PPI-based version.

If the DUMPTRACE_PID environment variable is set to a true value, this module will include process ID information with the file and line number in all trace output. This setting can be helpful in debugging multi-process programs (programs that fork). Since v0.23, the trace output when DUMPTRACE_PID is set also includes thread ID information.

If the DUMPTRACE_TIME environment variable is set to a true value, this module will include program runtime information with the file and line number in all trace output. Depending on the evaluation needs of each line of the code, the timestamp associated with a line may be created either immediately before or immediately after the line is executed.

If the DUMPTRACE_COUNT environment variable is set to a true value, this module will include a count with the file and line number in all trace output, indicating how many times your program has visited a particular line of code.

The default behaviour of Devel::DumpTrace is to include the name of the current subroutine each time the file and line number are displayed. If DUMPTRACE_NO_SUB environment variable is set to a true value, then the subroutine name will not be displayed.

DUMPTRACE_TIME, DUMPTRACE_PID, DUMPTRACE_COUNT, and DUMPTRACE_NO_SUB may be used separately or in any combination.

When more than one environment variable needs to be set, the caller can use the DUMPTRACE environment variable to set multiple variables concisely. If $ENV{DUMPTRACE} is set, this module will split the variable value into key value pairs and update the other relevant environment variables. That is,

    DUMPTRACE=PID=1,FH=trace.out,EXCLPKG=My::Module

is equivalent to the longer

    DUMPTRACE_PID=1 DUMPTRACE_FH=trace.out DUMPTRACE_EXCL=My::Module

If DUMPTRACE_COLOR is set, and if the Term::ANSIColor module can be loaded, then Devel::DumpTrace output will be colored in the specified color. If your program produces output and you are writing Devel::DumpTrace output to your console, the different color of the DumpTrace output will help the actual output from the program stand out.

Example:

    DUMPTRACE_COLOR="bold yellow on_black" perl -d:DumpTrace myScript.pl

INCOMPATIBILITIES

None known.

EXPORT

Nothing is exported from this module.

DIAGNOSTICS

All output from this module is for diagnostics.

DEPENDENCIES

PadWalker for arbitrary access to lexical variables.

Scalar::Util for the reference identification convenience methods.

BUGS AND LIMITATIONS

Parser limitations

Some known cases where the output of this module will be incorrect or misleading include:

Multiple statements on one line

    $b = 7;
    $a=4; $b=++$a;
    =================================
    >>>>>            4=4; 7=++undef;
    >>>>>            5=4; 7=++4;

All expressions on a line are evaluated, not just expressions in the statement currently being executed. Also see the basic parser limitation below concerning multiple lines for one statement.

Statements with chained assignments; complex assignment expressions

    ($a,$b) = ('','bar');
    $a = $b = 'foo';
    >>>>> 'foo' = 'bar' = 'foo';

    $rin=$ein=3;
    >>    select $rout=$in,undef,$eout=$ein,0;
    >>>   select $rout=3,undef,undef=3,0;
    >>>>> select 3=3,undef,undef=3,0;

Everything to the right of the first assignment operator in a statement is evaluated before the statement is executed.

Displayed value of @_ variable is unreliable

The displayed value of @_ inside a subroutine is subject to some of the issues described in "caller" in perlfunc:

    ... be aware that setting @DB::args is best effort, intended for
    debugging or generating backtraces, and should not be relied upon
    ... a side effect of the current implementation means that effects
    of shift @_ can normally be undone (but not pop @_ or other splicing,
    and not if a reference to @_ has been taken, and subject to the caveat
    about reallocated elements), so @DB::args is actually a hybrid of the
    current state and initial state of @_ . Buyer beware.

That is, the displayed value of @_ inside a subroutine may be corrupted. Different versions of Perl may have different behavior.

grep EXPR,LIST and map EXPR,LIST statements

grep EXPR,LIST and map EXPR,LIST constructions are evaluated a single time, after the entier LIST has been evaluated, and this module does not let you drill down to how each element of the list was evaluated with the given EXPR. The constructions grep BLOCK LIST and map BLOCK LIST, however, will display the BLOCK evaluation for each element of the LIST.

Basic parser limitations

This distribution ships with a PPI-based parser and a more basic parser that will be used if PPI is not available (or if you explicitly request to use the basic parser). This parser is quite crude compared to the PPI-based parser, and suffers from these additional known issues:

Multiple lines for one statement

    $a = ($b + $c                # ==> oops, all this module sees is
         + $d + $e);             #     $a = ($b + $c

Only the first line of code in an expression is evaluated.

String literals that contain variable names

    print STDERR "\$x is $x\n";  # ==> print STDERR "\4 is 4\n";
    $email = 'mob@cpan.org';     # ==> $email = 'mob().org'

The parser is not sophisticated enough to tell whether a sigil is inside non-interpolated quotes.

Implicit $_, @_

It would be nice if this parser could detect when Perl was implicitly using some variables and display the implicit variable.

    /expression/;        # actually  $_ =~ /expression/
    my $self = shift;    # actually  my $self = shift(@_);

That is not currently a capability of this module.

Special Perl variables are not recognized

    $a = join $/, 'foo', 'bar';  # ==> $a = join $/, 'foo', 'bar'

Special variables with pure alphanumeric names like @ARGV, $_, and $1 will still be interpolated. Do see "caller" in perlfunc for some important caveats about how @_ is represented by this module.

For some of these limitations, there are easy workarounds (break up chained assignments, put all statements on separate lines, etc.) if you think the extra information provided by this module is worth the effort to make your code more friendly for this module.

Other bugs or feature requests

Please report any other bugs or feature requests to bug-Devel-DumpTrace at rt.cpan.org, or through the web interface at http://rt.cpan.org/NoAuth/ReportBug.html?Queue=Devel-DumpTrace. I will be notified, and then you'll automatically be notified of progress on your bug as I make changes.

SUPPORT

You can find documentation for this module with the perldoc command.

    perldoc Devel::DumpTrace

You can also look for information at:

SEE ALSO

dumpvar.pl, as used by the Perl debugger.

Devel::Trace, PadWalker.

Devel::DumpTrace::PPI is part of this distribution and provides similar functionality using PPI to parse the source code.

Devel::TraceVars is a very similar effort to Devel::DumpTrace, but this module handles arrays, hashes, references, objects, lexical our variables, and addresses more edge cases.

Tie::Trace provides facilities to watch the values of specific variables, including stack trace information about where and how the variables values were changed.

Ideas from the Devel::GlobalDestruction module were used to manage output during the end game of the traced script.

AUTHOR

Marty O'Brien, <mob at cpan.org>

LICENSE AND COPYRIGHT

Copyright 2010-2019 Marty O'Brien.

This program is free software; you can redistribute it and/or modify it under the terms of either: the GNU General Public License as published by the Free Software Foundation; or the Artistic License.

See http://dev.perl.org/licenses/ for more information.