File Coverage

blib/lib/OpenTracing/WrapScope.pm
Criterion Covered Total %
statement 141 144 97.9
branch 56 62 90.3
condition 7 8 87.5
subroutine 27 27 100.0
pod 3 3 100.0
total 234 244 95.9


line stmt bran cond sub pod time code
1             package OpenTracing::WrapScope;
2             our $VERSION = 'v0.106.0';
3 14     14   7977849 use strict;
  14         126  
  14         391  
4 14     14   70 use warnings;
  14         29  
  14         356  
5 14     14   70 use warnings::register;
  14         23  
  14         1490  
6 14     14   520 use B::Hooks::EndOfScope;
  14         9708  
  14         122  
7 14     14   6612 use B::Hooks::OP::Check::StashChange;
  14         20611  
  14         415  
8 14     14   82 use Carp qw/croak/;
  14         27  
  14         633  
9 14     14   78 use List::Util qw/uniq/;
  14         26  
  14         697  
10 14     14   457 use OpenTracing::GlobalTracer;
  14         9422  
  14         81  
11 14     14   1279 use PerlX::Maybe;
  14         2096  
  14         119  
12 14     14   6081 use Sub::Info qw/sub_info/;
  14         86426  
  14         87  
13              
14             { # transparent caller, stolen from Hook::LexWrap
15 14     14   428 no warnings 'redefine';
  14         29  
  14         11146  
16             *CORE::GLOBAL::caller = sub (;$) {
17 432   100 432   79502 my ($height) = ($_[0]||0);
18 432         657 my $i=1;
19 432         708 my $name_cache;
20 432         583 while (1) {
21             my @caller = CORE::caller() eq 'DB'
22 793 100       4605 ? do { package DB; CORE::caller($i++) }
  10         35  
23             : CORE::caller($i++);
24 793 100       1853 return if not @caller;
25 775 100       1397 $caller[3] = $name_cache if $name_cache;
26 775 100       1423 $name_cache = $caller[0] eq __PACKAGE__ ? $caller[3] : '';
27 775 100 100     2506 next if $name_cache || $height-- != 0;
28 414 100       1925 return wantarray ? @_ ? @caller : @caller[0..2] : $caller[0];
    100          
29             }
30             };
31             }
32              
33             my @sub_sets; # leftover non-wrapped subs
34 14     14   59502 END { _warn_unwrapped(@sub_sets) }
35              
36             sub import {
37 15     15   144 shift; # __PACKAGE__
38 15         38 my $target_package = caller;
39              
40 15         35 my ($use_env, @subs, @files);
41 15         97 while (my (undef, $arg) = each @_) {
42 25 100       84 if ($arg eq '-env') {
    100          
43 2         6 $use_env = 1;
44             }
45             elsif ($arg eq '-file') {
46 2 50       8 my (undef, $next) = each @_ or last;
47 2 100       9 push @files, ref $next eq 'ARRAY' ? @$next : $next;
48             }
49             else {
50 21         62 push @subs, _qualify_sub($arg, $target_package);
51             }
52             }
53 15 50 66     57 if ($use_env and $ENV{OPENTRACING_WRAPSCOPE_FILE}) {
54 2         7 push @files, split ':', $ENV{OPENTRACING_WRAPSCOPE_FILE};
55             }
56 15         70 push @subs, map { _load_sub_spec($_) } grep { -f } map { glob } uniq @files;
  7         29  
  7         92  
  6         263  
57              
58 15         54 _setup_install_hooks(@subs);
59 15         236 return;
60             }
61              
62             sub _setup_install_hooks {
63 15     15   31 my %stashes;
64 15         32 foreach my $sub (@_) {
65 35         155 my ($stash) = $sub =~ s/(?:'|::)\w+\z//r;
66 35         107 $stashes{$stash}{$sub} = 1;
67             }
68 15         33 push @sub_sets, \%stashes;
69              
70             on_scope_end {
71 15     15   950 foreach my $stash (keys %stashes) {
72 11         37 _install_from_stash($stashes{$stash});
73 11 100       16 delete $stashes{$stash} if not %{ $stashes{$stash} };
  11         60  
74             }
75 15         134 };
76              
77 15         330 my $id;
78             my $installer = sub { # run when a new package is being compiled
79 1199     1199   3999008111 my ($new_stash) = @_;
80 1199 100       98741 return if not exists $stashes{$new_stash};
81              
82             on_scope_end { # check for wanted subs when it's done compiling
83 18 100       117 my $stash = $stashes{$new_stash}
84             or return; # might have been removed by another hook
85 11         40 _install_from_stash($stash);
86 11 100       50 delete $stashes{$new_stash} if not %$stash;
87 18         167 };
88              
89             # everything is installed, stop checking
90 18 50       2254 B::Hooks::OP::Check::StashChange::unregister($id) if not %stashes;
91 15         52 };
92 15         3442 $id = B::Hooks::OP::Check::StashChange::register($installer);
93              
94 15         63 return;
95             }
96              
97             sub _install_from_stash {
98 22     22   45 my ($stash) = @_;
99 22 50       67 return if not $stash;
100            
101 22         62 foreach my $sub (keys %$stash) {
102 39 100       138 next unless defined &$sub;
103 35         91 install_wrapped($sub);
104 35         97 delete $stash->{$sub};
105             }
106 22         60 return;
107             }
108              
109             sub install_wrapped {
110 39     39 1 861 foreach my $sub (@_) {
111 40         130 my $full_sub = _qualify_sub($sub, scalar caller);
112              
113 40 100       145 if (not defined &$sub) {
114 2         84 warnings::warn "Couldn't find sub: $sub";
115 1         25 next;
116             }
117              
118 14     14   110 no strict 'refs';
  14         30  
  14         483  
119 14     14   75 no warnings 'redefine';
  14         33  
  14         9486  
120 38         104 *$sub = wrapped(\&$sub);
121             }
122 38         75 return;
123             }
124              
125             sub wrapped {
126 38     38 1 70 my ($coderef) = @_;
127 38         101 my $info = sub_info($coderef);
128              
129             return sub {
130 46     46   10486 my ($call_package, $call_filename, $call_line) = caller(0);
131 46         204 my $call_sub = (caller(1))[3];
132 46         358 my $tracer = OpenTracing::GlobalTracer->get_global_tracer;
133             my $scope = $tracer->start_active_span(
134             "$info->{package}::$info->{name}",
135             tags => {
136             'source.subname' => $info->{name},
137             'source.file' => $info->{file},
138             'source.line' => $info->{start_line},
139             'source.package' => $info->{package},
140 46         772 maybe
141             'caller.subname' => $call_sub,
142             'caller.file' => $call_filename,
143             'caller.line' => $call_line,
144             'caller.package' => $call_package,
145             },
146             );
147              
148 46         42077 my $result;
149 46         103 my $wantarray = wantarray; # eval will have its own
150 46         81 my $ok = eval {
151 46 100       127 if (defined $wantarray) {
152 4 100       21 $result = $wantarray ? [&$coderef] : &$coderef;
153             }
154             else {
155 42         161 &$coderef;
156             }
157 45         8511 1;
158             };
159             # TODO: message should go to logs but we don't have those yet
160 46 100       179 $scope->get_span->add_tags(error => 1, message => "$@") unless $ok;
161 46         422 $scope->close();
162              
163 46 100       6473 die $@ unless $ok;
164 45 100       566 return if not defined wantarray;
165 4 100       58 return wantarray ? @$result : $result;
166 38         4134 };
167             }
168              
169             sub _qualify_sub {
170 61     61   216 my ($sub, $pkg) = @_;
171 61 100       373 return $sub if $sub =~ /'|::/;
172 16         66 return "${pkg}::$sub";
173             }
174              
175             sub _load_sub_spec {
176 10     10   22 my ($filename) = @_;
177              
178 10 50       317 open my $fh_subs, '<', $filename or die "$filename: $!";
179              
180 10         29 my @subs;
181 10         172 while (<$fh_subs>) {
182 19 100       65 next if /^\s*#/; # commented-out line
183 18         31 s/\s*#.*\Z//; # trailing comment
184 18         29 chomp;
185 18 100       125 croak "Unqualified subroutine: $_" if !/'|::/;
186 17         96 push @subs, $_;
187             }
188 9         87 close $fh_subs;
189              
190 9         61 return @subs;
191             }
192              
193             sub wrap_from_file {
194 3     3 1 3507 my ($filename) = @_;
195 3         9 install_wrapped( _load_sub_spec($filename) );
196 2         8 return;
197             }
198              
199             sub _warn_unwrapped {
200 14     14   59 foreach my $stash_set (@_) {
201 15 50       120 next if not %$stash_set;
202 0           foreach my $sub (map { keys %$_ } values %$stash_set) {
  0            
203 0           warnings::warn "OpenTracing::WrapScope didn't find sub: $sub";
204             }
205             }
206             }
207              
208              
209             1;