Как получить список стеков вызовов в Perl?

54

Есть ли способ, которым я могу получить доступ (для распечатки) список суб + модуля к произвольной глубине подзаголовков, предшествующих текущей позиции в Perl script?

Мне нужно внести изменения в некоторые модули Perl (.pm's). Рабочий процесс инициируется с веб-страницы через cgi- script, передавая вход через несколько модулей/объектов, заканчивающихся в модуле, где мне нужно использовать данные. Где-то вдоль линии данные менялись, и мне нужно выяснить, где.

  • 0
    Хотя это не отвечает на ваш вопрос, это может помочь вам решить вашу проблему :-) Вот интересная статья, описывающая один способ выяснить, кто меняет ваши переменные по сравнению с Марком Доминусом
Теги:
stack-trace
callstack

7 ответов

55
Лучший ответ

Вы можете использовать Devel:: StackTrace.

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

Он ведет себя как следы Carp, но вы можете получить больше контроля над кадрами.

Одна проблема заключается в том, что ссылки стробируются, и если ссылочное значение изменяется, вы не увидите его. Тем не менее, вы можете взломать некоторые вещи с помощью PadWalker, чтобы распечатать полные данные (это было бы огромно, хотя).

  • 2
    Очень полезная альтернатива: perl -d:Confess script.pl из perl -d:Confess script.pl :: Confess .
17

caller может сделать это, хотя вам может понадобиться еще больше информации.

15

Там также Carp::confess и Carp::cluck.

14

Carp::longmess будет делать то, что вы хотите, и стандартно.

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
';

Я придумал этот суб (теперь с дополнительным благословением!)

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;
}
  • 1
    longmess больше не является документированной или автоматически экспортируемой функцией Carp. Однако: my $mess = carp(); обеспечит похожее, но не идентичное поведение.
7

Пока это не отвечает на ваш вопрос, это может помочь вам решить вашу проблему: -)

Вот интересная статья, описывающая один из способов выяснить, кто изменяет ваши переменные из Mark Dominus

6

Этот код работает без каких-либо дополнительных модулей. Просто включите его там, где это необходимо.

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";
}
  • 0
    изящная техника (хотя я должен сказать, что это было давно, так как я баловался с Perl :)
  • 1
    Очень приятно сказать! Спасибо :-)
1

То, что более красиво: Devel::PrettyTrace

use Devel::PrettyTrace;
bt;

Ещё вопросы

Сообщество Overcoder
Наверх
Меню