2008-10-23 9 views
53

Esiste un modo per accedere (per la stampa) a un elenco di sub + modulo alla profondità arbitraria delle sub-chiamate che precedono una posizione corrente in uno script Perl?Come posso ottenere un elenco di stack di chiamate in Perl?

Ho bisogno di apportare modifiche ad alcuni moduli Perl (.pm's). Il flusso di lavoro viene avviato da una pagina Web attraverso uno script cgi, passando l'input attraverso diversi moduli/oggetti che terminano nel modulo in cui ho bisogno di utilizzare i dati. Da qualche parte lungo la linea i dati sono cambiati e ho bisogno di scoprire dove.

risposta

56

È possibile utilizzare Devel::StackTrace.

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

Si comporta come la traccia di Carp, ma è possibile ottenere un maggiore controllo sui fotogrammi.

L'unico problema è che i riferimenti sono stringificati e se un valore di riferimento cambia, non lo vedrai. Tuttavia, è possibile creare alcune cose con PadWalker per stampare i dati completi (sarebbe comunque enorme).

17

caller può farlo, anche se potrebbe volere anche più informazioni di quello.

7

Anche se questo non risponde alla tua domanda potrebbe aiutare a risolvere il problema :-)

Ecco un interessante articolo che descrive un modo per capire chi cambia le variabili da Mark Dominus

+0

Dovrò trovare il tempo di leggere l'articolo - sembra davvero interessante. – slashmais

15
C'è

anche Carp::confess e Carp::cluck.

14

Carp::longmess farà quello che vuoi, ed è 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 
'; 

sono arrivato fino a questo sub

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 non è più una funzionalità documentata o esportata automaticamente di Carp. Tuttavia: 'my $ mess = carp();' fornirà un comportamento simile ma non identico. –

8

questo codice funziona senza alcun ulteriore moduli. Basta includerlo dove necessario.

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

tecnica ordinata (anche se devo dire che è passato un po 'di tempo da quando mi sono dilettato con Perl :) – slashmais

+1

Molto bello che ho da dire! Grazie :-) – frr

Problemi correlati