2008-10-23 13 views
53

Existe-t-il un moyen d'accéder (pour l'impression) à une liste de sub + module à la profondeur arbitraire des sous-appels précédant une position actuelle dans un script Perl?Comment puis-je obtenir une liste de piles d'appels en Perl?

Je dois apporter des modifications à certains modules Perl (.pm). Le flux de travail est initié à partir d'une page Web à travers un script cgi, en passant l'entrée à travers plusieurs modules/objets se terminant dans le module où j'ai besoin d'utiliser les données. Quelque part le long de la ligne les données ont changé et j'ai besoin de savoir où.

Répondre

56

Vous pouvez utiliser Devel::StackTrace. Il se comporte comme la trace de Carp, mais vous pouvez obtenir plus de contrôle sur les images.

Le seul problème est que les références sont stringifiées et si une valeur référencée change, vous ne le verrez pas. Cependant, vous pouvez ajouter quelques éléments avec PadWalker pour imprimer les données complètes (ce serait énorme, cependant).

17

caller peut le faire, même si vous pouvez vouloir encore plus d'informations que cela.

7

Bien que cela ne répond pas à votre question, il peut vous aider à résoudre votre problème :-)

Voici un article intéressant qui décrit d'une façon comment déterminer qui change vos variables de Mark Dominus

+0

Je vais devoir prendre le temps de lire l'article - semble intéressant en effet. – slashmais

15

Il y a aussi Carp::confess et Carp::cluck.

14

Carp::longmess fera ce que vous voulez, et c'est 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 
'; 

je suis venu avec ce sous

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 n'est plus une fonctionnalité documentée ou automatiquement exportée de Carp. Cependant: 'mon $ mess = carpe();' fournira un comportement similaire mais pas identique. –

8

Ce code fonctionne sans plus modules. Il suffit de l'inclure si nécessaire.

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

technique soigné (même si je dois dire que ça fait longtemps que je ne me suis pas amusé avec Perl :) – slashmais

+1

Très sympa je dois dire! Je vous remercie :-) – frr