Tutorial :How can I find the source location of a print statement in Perl?



Question:

How can I find the source location of a print statement in Perl?

#!/usr/bin/perl    foo();  bar();    sub foo {    print "foo\n";  }    sub bar {    print "bar\n";  }  

The output being:

>perl test.pl   foo  bar  

I'd like to somehow find be able to see (or something like)

>perl test.pl   main::foo> foo  main::bar> bar  

The reason for this is I'm trying to track down some rouge output, and cannot find its location in a large code base.


Solution:1

Try this:

#!/usr/bin/env perl    use strict;  use warnings;  use Tie::STDOUT print => sub {    my ( $pkg, $file, $line ) = caller(2);    print "$pkg, $file, $line :: ", @_;  };    print "Hello, World\n";  

Which gives:

$ perl tp.pl  main, tp.pl, 10 :: Hello, World  

Update: I've just released Devel::Ditto:

$ perl -MDevel::Ditto myprog.pl  [main, t/myprog.pl, 9] This is regular text  [main, t/myprog.pl, 10] This is a warning  [MyPrinter, t/lib/MyPrinter.pm, 7] Hello, World  [MyPrinter, t/lib/MyPrinter.pm, 8] Whappen?  


Solution:2

Use Debug::Trace ( https://metacpan.org/pod/Debug::Trace )

#!/usr/bin/perl    foo();  bar();    sub foo {    print "foo\n";  }    sub bar {    print "bar\n";  }  

This program, saved as test.pl and called as:

perl -MDebug::Trace=foo,bar test.pl  

Prints out:

TRACE:  main::foo() called at test.pl line 3 package main  foo  TRACE:  main::foo() returned  TRACE:  main::bar() called at test.pl line 4 package main  bar  TRACE:  main::bar() returned  


Solution:3

I knew source filters could be useful for something:

C:\Temp> cat DebugFilter.pm  package DebugFilter;    use strict;  use warnings;    use Filter::Simple;    FILTER_ONLY      code_no_comments => sub {          s/print/main::mydebugfn();print/g      };    1;  __END__    C:\Temp> cat DebugPrint.pm  package DebugPrint;    use strict;  use warnings;    use base qw( Exporter );    our @EXPORT = qw( mydebugfn );    sub mydebugfn {      my ( $pkg, $fn, $line, $sub ) = caller(2);      warn "print called from: ${sub}(${fn}:${line})\n";  }    1;  __END__    C:\Temp> cat t.pl  #!/usr/bin/perl    use strict;  use warnings;    use DebugFilter;    sub test {      print STDOUT "print in test\n";      return;  }    test();  

Here is the output:

C:\Temp> perl -MDebugPrint t.pl  print called from: main::test(t.pl:13)  print in test  


Solution:4

Copas: I can't reply to your comment directly (not yet "cool" enough) but the basic problem is that any decent sized project is not one .pl file. It's a bunch of modules all being pulled in together.

Your code:

a) doesn't address anything outside the one .pl file b) doesn't handle cases where print(...) has brackets or different spacing. c) doesn't cope with cases where the first argument to print is a function call or variable rather than a double-quoted string. d) consider: $object->log("Am about to print " . foo($var) . " to the console"); - your regex would cause a syntax error, making this: $object->log("Am about to print "Line 1084: . $foo($var) . " to the console");

That said, it's viable for simple scripts. It's not a BAD idea (worst case, your newsource.pl doesn't compile) - but it's not going to fix this particular problem unless it's all in one file.


Solution:5

This article explains how to hook into perl print function: How can I hook into Perl's print?

You may need it, if you don't want to replace all the print statements in your source code with something else.


Solution:6

I am going to leave the source filter alternative up for reference because it is geared towards tracing the invocation of a single function.

However, the solution seems to be to use Devel::Trace. This will presumably generate a lot of output which you can redirect to a file and then grep for the offending output.

C:\Temp> perl -d:Trace t.pl  >> t.pl:10: T::test();  >> T.pm:5:     print "in T::test\n";  in T::test  >> c:/opt/perl/lib/Config.pm:63: sub DESTROY { }  


Solution:7

You could try stepping through your code with the debugger (perl -d).

I was going to suggest overriding print and using:

($package, $filename, $line) = caller;  

...to print out the extra info, but it turns out print is one of the builtins that can't be overridden.


Solution:8

You could try using Hook::LexWrap to dig down into what's calling what in your codebase. It does some pretty evil things internally, so won't work for all codebases.


Note:If u also have question or solution just comment us below or mail us on toontricks1994@gmail.com
Previous
Next Post »