2008-10-23 14 views
53

¿Hay alguna manera de que pueda acceder (para imprimir) una lista de sub + módulo a profundidad arbitraria de sub llamadas que preceden a una posición actual en una secuencia de comandos de Perl?¿Cómo puedo obtener una lista de pila de llamadas en Perl?

Necesito hacer cambios en algunos módulos de Perl (.pm). El flujo de trabajo se inicia desde una página web a través de un script cgi, pasando la entrada a través de varios módulos/objetos que terminan en el módulo donde necesito usar los datos. En algún momento, los datos se cambiaron y necesito averiguar dónde.

Respuesta

56

Puede usar Devel::StackTrace.

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

Se comporta como la traza de Carp, pero puede obtener más control sobre los marcos.

El único problema es que las referencias están codificadas y si un valor de referencia cambia, no lo verá. Sin embargo, podría actualizar algunas cosas con PadWalker para imprimir la información completa (sin embargo, sería enorme).

17

caller puede hacerlo, aunque es posible que desee obtener más información que eso.

7

Si bien esto no responde a su pregunta podría ayudar a resolver su problema :-)

Aquí es un interesante artículo que describe una manera de cómo averiguar que cambia sus variables de Mark Dominus

+0

Tendré que darme tiempo para leer el artículo, parece realmente interesante. – slashmais

15

También hay Carp::confess y Carp::cluck.

14

Carp::longmess hará lo que quiera, y es estándar.

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

me ocurrió con esta 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 ya no es una característica documentada o exportada automáticamente de Carp. Sin embargo: 'my $ mess = carp();' proporcionará un comportamiento similar pero no idéntico. –

8

Este código funciona sin ningún adicional módulos. Simplemente inclúyalo donde sea necesario.

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

técnica ordenada (aunque debo decir que ha pasado un tiempo desde que empecé con Perl :) – slashmais

+1

¡Muy bien, tengo que decirlo! Gracias :-) – frr

Cuestiones relacionadas