File Coverage

lib/Devel/CallStack.pm
Criterion Covered Total %
statement 33 74 44.5
branch 17 52 32.6
condition 1 3 33.3
subroutine 9 13 69.2
pod 1 6 16.6
total 61 148 41.2


line stmt bran cond sub pod time code
1             package Devel::CallStack;
2              
3             require 5.006001;
4              
5 2     2   1843 use strict;
  2         5  
  2         125  
6              
7 2         2615 use vars qw($VERSION
8             $Depth $Full $Reverse $Stdout $Stderr $Out $In $Append
9             $Import
10 2     2   14 %Cumul);
  2         6  
11              
12             $VERSION = '0.19';
13             $Depth = 1e9; # If someone has a callstack this deep, we are in trouble.
14             $Import = 0;
15              
16             sub import {
17 2     2   75 my $class = shift;
18 2         6 for my $i (@_) {
19 1 50       34 if ($i =~ /^(?:depth=)?(\d+)$/) {
    50          
    50          
    50          
    50          
    50          
    50          
    50          
20 0         0 $Depth = $1;
21             } elsif ($i eq 'full') {
22 0         0 $Full = 1;
23             } elsif ($i eq 'reverse') {
24 0         0 $Reverse = 1;
25             } elsif ($i eq 'stdout') {
26 0         0 $Stdout = 1;
27             } elsif ($i eq 'stderr') {
28 0         0 $Stderr = 1;
29             } elsif ($i =~ /^out=(.+)/) {
30 0         0 $Out = $1;
31             } elsif ($i =~ /^in(?:=(.+))?/) {
32 0 0       0 $In = $1 ne "" ? $1 : "callstack.out";
33             } elsif ($i eq 'append') {
34 0         0 $Append = 1;
35             } else {
36 1         13 die "Devel::CallStack::import: '$i' unknown\n";
37             }
38             }
39 1         5 &set(); # Otherwise we get the import() call stack captured, too.
40 1 50       5 &read($In) if defined $In;
41 1 50 33     9 $Out = "callstack.out" unless defined $Out || $Stdout;
42 1         12 $Import++; # Import was a success.
43             }
44              
45             sub set {
46 1     1 0 3 %Cumul = @_;
47             }
48              
49             sub get {
50 0     0 0 0 %Cumul;
51             }
52              
53             sub write {
54 2 100   2 0 17 if ($Import) {
55 1         2 my $ofh;
56 1 50       8 if ($Stdout) {
    50          
    50          
57 0         0 $ofh = select STDOUT;
58             } elsif ($Stderr) {
59 0         0 $ofh = select STDERR;
60             } elsif (defined $Out) {
61 1 50       5 my $mode = $Append ? ">>" : ">";
62 1 50       141 unless (open(OUT, "$mode$Out")) {
63 0         0 die qq[Devel::CallStack::END: failed to open "$Out" for writing: $!\n];
64             }
65 1         7 $ofh = select OUT;
66             }
67 1         7 for my $s (sort keys %Cumul) {
68 0 0       0 next if $s =~ /Devel::CallStack/o; # We do not exist.
69 0         0 my $d = ($s =~ tr/,/,/) + 1;
70 0         0 print "$s $d $Cumul{$s}\n";
71             }
72 1         10 select $ofh;
73             }
74             }
75              
76             sub read {
77 0     0 0   my $fn = shift;
78 0 0         unless (open(IN, $fn)) {
79 0           die qq[Devel::CallStack::read: failed to open "$fn" for reading: $!\n];
80             }
81 0           while () {
82 0           my ($s, $d, $n) = split;
83 0 0         $s = join(",", reverse split(/,/, $s)) if $Reverse;
84 0           $Cumul{$s} += $n;
85             }
86 0           close(IN);
87             }
88              
89             sub END {
90 2     2   2539 &write();
91             }
92              
93             package DB;
94              
95 2     2   34 use strict;
  2         5  
  2         112  
96              
97 0     0 0   sub DB { }
98              
99 2     2   10 use vars qw($Full $Depth $Reverse %Cumul);
  2         4  
  2         1020  
100              
101             *Depth = \$Devel::CallStack::Depth;
102             *Full = \$Devel::CallStack::Full;
103             *Reverse = \$Devel::CallStack::Reverse;
104             *Cumul = \%Devel::CallStack::Cumul;
105              
106             sub sub {
107 0 0   0 1   if (my ($p, $s) = ($DB::sub =~ /^(.+)::(.+)/)) {
108 0           my @s;
109 0 0         if ($Full) {
110 0 0         if (my ($f, $l) = ($DB::sub{$DB::sub} =~ /^(.+):(\d+)/)) {
111 0           @s = ( "$f:$l:${p}::$s" );
112 0           for (my $i = 0; @s < $Depth; $i++) {
113 0           my @c = caller($i);
114 0 0         last unless @c;
115 0           push @s, "$c[1]:$c[2]:$c[3]";
116             }
117             }
118             } else {
119 0           @s = ( $DB::sub );
120 0           for (my $i = 0; @s < $Depth; $i++) {
121 0           my @c = caller($i);
122 0 0         last unless @c;
123 0           push @s, $c[3];
124             }
125             }
126             $Cumul{
127 0 0         join ",", $Reverse ? @s : reverse @s # Ironic, no?
128             }++;
129             }
130 2     2   14 no strict 'refs';
  2         4  
  2         294  
131 0           &{$DB::sub}(@_);
  0            
132             }
133              
134             1;
135             __END__