2008-10-23 9 views
53

Gibt es einen Weg, auf den ich zugreifen kann (für den Ausdruck) eine Liste von sub + Modul zu beliebiger Tiefe von Unteraufrufen vor einer aktuellen Position in einem Perl-Skript?Wie kann ich eine Anrufliste in Perl abrufen?

Ich muss Änderungen an einigen Perl-Modulen (.pm) vornehmen. Der Workflow wird von einer Webseite über ein CGI-Skript initiiert, wobei die Eingabe durch mehrere Module/Objekte erfolgt, die in dem Modul enden, in dem ich die Daten verwenden muss. Irgendwo entlang der Linie wurden die Daten geändert und ich muss herausfinden, wo.

Antwort

56

Sie können Devel::StackTrace verwenden.

Es verhält sich wie Carp-Trace, aber Sie können mehr Kontrolle über die Frames erhalten.

Das einzige Problem ist, dass Referenzen mit einem String versehen werden und wenn sich ein referenzierter Wert ändert, werden Sie ihn nicht sehen. Sie könnten jedoch einige Sachen mit PadWalker aufpinseln, um die vollen Daten auszudrucken (es wäre jedoch riesig).

17

caller kann das tun, obwohl Sie vielleicht noch mehr Informationen als das wollen.

7

Während dies Ihre Frage nicht beantworten, es könnte Ihnen Ihr Problem lösen helfen :-)

Hier ein interessanter Artikel ist eine Möglichkeit, die beschreiben, wie um herauszufinden, wer Ihre Variablen von Mark Dominus

+0

Ich werde Zeit brauchen, um den Artikel zu lesen - scheint in der Tat interessant. – slashmais

15

Es gibt auch Änderungen Carp::confess und Carp::cluck.

14

Carp::longmess wird tun, was Sie wollen, und es ist Standard.

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

Ich kam mit dieser Unter bis

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 ist nicht länger eine dokumentierte oder automatisch exportierte Funktion von Carp. Jedoch: 'my $ mess = carp();' wird ähnliche, aber nicht identische Verhalten bieten. –

8

Dieser Code funktioniert ohne zusätzliche Module. Fügen Sie es einfach hinzu, wo es gebraucht wird.

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

ordentliche Technik (obwohl ich sagen muss, dass es schon eine Weile her ist, seit ich mich mit Perl beschäftigt habe :) – slashmais

+1

Sehr schön muss ich sagen! Vielen Dank :-) – frr

Verwandte Themen