How can I get a call stack list in Perl?

Is there a way that I can access (for printing) a list of sub + modules to an arbitrary depth of subheadings preceding the current position in a Perl script?

I need to make changes to some Perl modules (.pm's). The workflow is initiated from the web page through a cgi- script, passing input through several modules / objects ending in the module where I need to use the data. Somewhere along the line, the data was changing, and I need to find out where.

+60
stack-trace callstack perl
Oct 23 '08 at 8:53
source share
8 answers

You can use Devel :: StackTrace .

use Devel::StackTrace; my $trace = Devel::StackTrace->new; print $trace->as_string; # like carp 

It behaves like Carp tracks, but you can get more control over frames.

One problem is that the links are gated, and if the reference value changes, you will not see it. However, you can hack some things with PadWalker to print out the full data (that would be huge, though).

+59
Oct 23 '08 at 8:59
source share

caller can do this, although you may need even more information.

+18
Oct 23 '08 at 9:01
source share

Carp::longmess will do what you want, and standardly.

 use Carp qw<longmess>; use Data::Dumper; sub A { &B; } sub B { &C; } sub C { &D; } sub D { &E; } sub E { # Uncomment below if you want to see the place in E # local $Carp::CarpLevel = -1; my $mess = longmess(); print Dumper( $mess ); } A(); __END__ $VAR1 = ' at - line 14 main::D called at - line 12 main::C called at - line 10 main::B called at - line 8 main::A() called at - line 23 '; 

I came up with this sub (now with extra blessing!)

 my $stack_frame_re = qr{ ^ # Beginning of line \s* # Any number of spaces ( [\w:]+ ) # Package + sub (?: [(] ( .*? ) [)] )? # Anything between two parens \s+ # At least one space called [ ] at # "called" followed by a single space \s+ ( \S+ ) \s+ # Spaces surrounding at least one non-space character line [ ] (\d+) # line designation }x; sub get_stack { my @lines = split /\s*\n\s*/, longmess; shift @lines; my @frames = map { my ( $sub_name, $arg_str, $file, $line ) = /$stack_frame_re/; my $ref = { sub_name => $sub_name , args => [ map { s/^'//; s/'$//; $_ } split /\s*,\s*/, $arg_str ] , file => $file , line => $line }; bless $ref, $_[0] if @_; $ref } @lines ; return wantarray ? @frames : \@frames; } 
+18
Oct 23 '08 at 10:50
source share

There's also Carp::confess and Carp::cluck .

+16
Oct 23 '08 at 9:53
source share

This code works without any additional modules . Just turn it on where necessary.

 my $i = 1; print STDERR "Stack Trace:\n"; while ( (my @call_details = (caller($i++))) ){ print STDERR $call_details[1].":".$call_details[2]." in function ".$call_details[3]."\n"; } 
+16
Aug 18 '16 at 6:59
source share

Until this answers your question, it can help you solve your problem :-)

Here's an interesting article describing one way to find out who is modifying your variables from Mark Dominus

+7
23 Oct '08 at 9:01
source share

What is more beautiful: Devel :: PrettyTrace

 use Devel::PrettyTrace; bt; 
+3
Jul 18 '14 at 10:28
source share

If you cannot use (or would like to avoid) non-core modules, here is a simple routine that I came up with:

 #!/usr/bin/perl use strict; use warnings; sub printstack { my ($package, $filename, $line, $subroutine, $hasargs, $wantarray, $evaltext, $is_require, $hints, $bitmask, $hinthash); my $i = 1; my @r; while (@r = caller($i)) { ($package, $filename, $line, $subroutine, $hasargs, $wantarray, $evaltext, $is_require, $hints, $bitmask, $hinthash) = @r; print "$filename:$line $subroutine\n"; $i++; } } sub i { printstack(); } sub h { i; } sub g { h; } g; 

It produces a conclusion as follows:

 /root/_/1.pl:21 main::i /root/_/1.pl:25 main::h /root/_/1.pl:28 main::g 

Or insert:

 for (my $i = 0; my @r = caller($i); $i++) { print "$r[1]:$r[2] $r[3]\n"; } 

You can find the documentation for the subscriber here .

+1
Jun 14 '19 at 10:48
source share



All Articles