6

I would like to trace my Perl script, but only code in the main package, and redirect output to a file.

When starting the script with perl -d script.pl it goes into interactive mode.

I have tried

perl -d:Trace perl_05.pl 2&> output.log

But this also traces all subroutines and modules which I do not want.

I am looking for something like the bash set -o xtrace or sh -x.

Borodin
  • 126,100
  • 9
  • 70
  • 144
averlon
  • 325
  • 3
  • 14
  • Possible duplicate of [Is there a way to turn on tracing in perl equivalent to bash -x?](http://stackoverflow.com/questions/3852395/is-there-a-way-to-turn-on-tracing-in-perl-equivalent-to-bash-x) – LaintalAy May 03 '16 at 07:42
  • 1
    [Trace your Perl programs](http://www.effectiveperlprogramming.com/2011/11/trace-your-perl-programs/) – LaintalAy May 03 '16 at 07:45
  • 1
    @eballes: Excellent. I think you should expand on that and post it as an answer – Borodin May 03 '16 at 08:17
  • @eballes: thanks; I already thought it would not be that simple as in bash; hard stuff for a newbie but I will bite through! – averlon May 03 '16 at 08:47

2 Answers2

6

The article Trace your Perl programs addresses your concerns regarding the amount of traces and shows you a way to tune the output so you just trace what you want.

You can create your own throw-away module to trace exactly what you want. Since the current directory is usually already in @INC, you can create a Devel/MyTrace.pm.

Read it completely to see how the author modifies the default behavior of the trace function to output first the traces to a file, then to STDERR too and finally limits the output to just trace the primary file.

You can go one step further to exclude all code except for the primary file:

use v5.10;
use autodie;

BEGIN {

my $trace_file = $ENV{TRACE_FILE} // "mytrace.$$";
print STDERR "Saving trace to $trace_file\n";

my $fh = do {
     if( $trace_file eq '-'      ) { \*STDOUT }
  elsif( $trace_file eq 'STDERR' ) { \*STDERR }
  else { 
      open my $fh, '>>', $trace_file;
      $fh;
      }
  };

sub DB::DB {
  my( $package, $file, $line ) = caller;
  return unless $file eq $0;
  my $code = \@{"::_<$file"};
  print $fh "[@{[time]}] $file $l $code->[$line]";
  }
}

1;

That last chunk of code is the one that is specially interesting for you. It does exactly what you want.

LaintalAy
  • 1,162
  • 2
  • 15
  • 26
  • now I need to find out how to include the module. I have tried #!/usr/bin/perl use strict; use warnings; use utf8; use "mytrace.pm"; but get a syntx error - will see! – averlon May 03 '16 at 09:09
  • 1
    You have to put it in a _Devel_ directory and then run Perl with `perl -d:mytrace foo.pl` where _mytrace_ refers to your _mytrace.pm_ file, which is in the _Devel_ directory. – simbabque May 03 '16 at 09:13
  • O.K. success; but still 1000+ lines of trace where the script probably has less then 100. – averlon May 03 '16 at 09:51
  • You also have to ask yourself what you want to achieve with this. Do you want to see what gets called when, or if some piece of code ever gets called? Or something else? That might be worth including in the question. – simbabque May 03 '16 at 10:00
  • for me as a newbie the answer is simple: just the same as sh -x; in other words a trace of all "my" satements of my program/script. If some statements calls a method I normally take the result to a variable and can let my program show it myself if needed. I normally (within bash) set a param like --debug to start the script and have some debugging prints/echo based on condition of the param [[ "$debug" ]] && echo "...". I was on the way to do the same in perl. Anyhow I would like to see my own statements - but none of the methods called. – averlon May 03 '16 at 11:32
  • or just perl -d with command n - that all looks to me as this is the same as what I know from sh -x. – averlon May 03 '16 at 11:41
  • 1
    @averlon how should it know which lines are yours? You might want to look into https://metacpan.org/pod/Devel::Comments and combine that with the Devel::mytrace approach. Or maybe with a git blame in the `DB::DB` function? So many possibilities... – simbabque May 03 '16 at 13:04
5

Using perl with Devel::DumpTrace is a lot like using bash -x. Like bash -x, Devel::DumpTrace expands and outputs variable values to give you an idea of what your script was doing, not just where it is doing it.

It also has the feature you are looking for: to enable and disable tracing on specific packages. For your use case, you would run it like

perl -d:DumpTrace=-.*,+main my_script.pl

or

perl -d:DumpTrace=-.* my_script.pl

-.* means "exclude all packages that match /^.*$/ from tracing", which is to say, all packages. +main means "include package main in tracing".

The default output can be fairly verbose. If you want less output than that, you can specify quiet mode:

perl -d:DumpTrace=quiet,-.*,+main my_script.pl

(I am the author of Devel::DumpTrace)

mob
  • 117,087
  • 18
  • 149
  • 283