File Coverage

blib/lib/IO/Lambda/Backtrace.pm
Criterion Covered Total %
statement 37 60 61.6
branch 10 22 45.4
condition 3 3 100.0
subroutine 8 12 66.6
pod 4 9 44.4
total 62 106 58.4


line stmt bran cond sub pod time code
1             package IO::Lambda::Backtrace;
2             # $Id: Backtrace.pm,v 1.3 2010/01/01 14:49:02 dk Exp $
3 1     1   5 use strict;
  1         2  
  1         31  
4 1     1   5 use warnings;
  1         2  
  1         39  
5 1     1   5 use IO::Lambda qw(:constants :dev);
  1         2  
  1         937  
6              
7             sub new
8             {
9 6     6 1 177 my ( $class, $this, $caller) = @_;
10 6         14 my @stacks = make_lambda_stacks($this);
11 6 50       20 $caller = Carp::shortmess unless defined $caller;
12 6         12 my @entry = ($this, $caller);
13 6         19 unshift @$_, \@entry for @stacks;
14 6 100       15 @stacks = [\@entry] unless @stacks;
15 6         33 bless \@stacks, $class;
16             }
17              
18 6     6 0 17 sub events2lambdas { @$_ = map { [ $_-> [WATCH_OBJ], $_-> [WATCH_CALLER] ] } @$_ for @_; @_ }
  15         52  
  6         15  
19 20     20 0 54 sub make_event_tree { map { [ $_, make_event_tree( $_->[WATCH_OBJ] ) ] } shift-> callers }
  14         31  
20 0     0 0 0 sub make_event_stacks { tree2stacks ( make_event_tree ( shift )) }
21 6     6 0 13 sub make_lambda_stacks { events2lambdas( tree2stacks( make_event_tree( shift ))) }
22              
23             sub tree2stacks
24             {
25 6     6 0 11 my @tracks = @_;
26 6         8 my (@finished, @current, @stack);
27 6   100     40 while (@stack or @tracks) {
28 17 100       37 if ( @tracks) {
29 14         18 my $p = shift @tracks;
30 14 100       33 push @stack, [ @current ], [ @tracks ]
31             if @tracks;
32 14         20 push @current, shift @$p;
33 14         61 @tracks = @$p;
34             } else {
35 3 50       11 push @finished, [ @current ] if @current;
36 3         5 @tracks = @{ pop @stack };
  3         6  
37 3         87 @current = @{ pop @stack };
  3         17  
38             }
39             }
40 6 100       19 push @finished, [ @current ] if @current;
41 6         19 return @finished;
42             }
43              
44             sub as_text
45             {
46 0     0 1   my $self = shift;
47 0           my $out = '';
48 0           my $ch = 1;
49 0           for ( @$self ) {
50 0           my $depth = 0;
51 0           for ( @$_ ) {
52 0           $depth++;
53 0 0         $out .= "\t #$ch/$depth: "
54             if $IO::Lambda::DEBUG_CALLER;
55 0           $out .= 'lambda(' . _o($_->[0]) . ')';
56             $out .= " created at $_->[0]->{caller}"
57 0 0         if $_->[0]->{caller};
58 0 0         if ( $depth == 1) {
    0          
    0          
59 0           $out .= " called";
60 0           $out .= $_->[1];
61             } elsif ( defined $_-> [1]) {
62 0           $out .= " awaited";
63 0           $out .= $_->[1];
64             } elsif ( $IO::Lambda::DEBUG_CALLER) {
65 0           $out .= "\n";
66             } else {
67 0           $out .= " ";
68             }
69             }
70 0           $out .= "\n";
71 0           $ch++;
72             }
73 0           return $out;
74             }
75              
76 0     0 1   sub cluck { warn shift-> as_text }
77 0     0 1   sub confess { die shift-> as_text }
78              
79             1;
80              
81             =pod
82              
83             =head1 NAME
84              
85             IO::Lambda::Backtrace - backtrace chains of events
86              
87             =head1 DESCRIPTION
88              
89             The module makes it easier to debug chains of events, when a lambda awaits for
90             another, this one in turn for another, etc etc. The class
91             C represents a set of such stacks, because a lambda can
92             be awaited by more than one lambda. Each stack is an array of items where each
93             contains the caller lambda and the invocation point. The class provides helper
94             methods for printing this information in readable form.
95              
96             The module relies on the debug information about invocation points collected by
97             C. By default, there's very little information collected, so in
98             order to increase verbosity use C flag, either
99             directly or through C<$ENV{IO_LAMBDA_DEBUG} = 'caller'>. If the flag is set to
100             1, lambdas collect invocation points. If the flag is set to 2, then also the
101             additional perl stack trace is added.
102              
103             =head1 SYNOPSIS
104              
105             use IO::Lambda;
106             $IO::Lambda::DEBUG_CALLER = 1;
107              
108             lambda {
109             ...
110             warn this-> backtrace-> as_text;
111             }
112              
113             or from command line
114              
115             env IO_LAMBDA_DEBUG=caller=2 ./myscript
116              
117             =head1 API
118              
119             =over
120              
121             =item new($lambda)
122              
123             Extracts the information of the current chain of events and creates a new blessed reference of it.
124              
125             =item as_text
126              
127             Returns the backtrace information formatted as text, ready to display
128              
129             =item cluck
130              
131             Warns with the backtrace log
132              
133             =item confess
134              
135             Dies with the backtrace log
136              
137             =back
138            
139             =head1 AUTHOR
140              
141             Dmitry Karasik, Edmitry@karasik.eu.orgE.
142              
143             The ideas of backtracing threads of events, and implementing backtrace objects
144             passable through execition stack are proposed by Ben Tilly.
145              
146             =cut