File Coverage

blib/lib/OpenTracing/Role/Span.pm
Criterion Covered Total %
statement 92 94 97.8
branch 28 34 82.3
condition 5 9 55.5
subroutine 25 26 96.1
pod 13 14 92.8
total 163 177 92.0


line stmt bran cond sub pod time code
1             package OpenTracing::Role::Span;
2              
3             our $VERSION = 'v0.86.1';
4              
5              
6              
7 16     16   2070429 use Moo::Role;
  16         18923  
  16         110  
8 16     16   13172 use MooX::HandlesVia;
  16         14383  
  16         140  
9 16     16   9192 use MooX::ProtectedAttributes;
  16         12572  
  16         123  
10 16     16   7187 use MooX::Should;
  16         47845  
  16         117  
11              
12 16     16   1729 use Carp;
  16         42  
  16         905  
13 16     16   6443 use OpenTracing::Types qw/:types :is/;
  16         1815593  
  16         136  
14 16     16   40370 use Time::HiRes qw/time/;
  16         45  
  16         169  
15 16     16   3250 use Types::Standard qw/CodeRef HashRef Maybe Num Object Str Value/;
  16         68  
  16         159  
16 16     16   61571 use Types::Common::Numeric qw/PositiveOrZeroNum/;
  16         339558  
  16         156  
17              
18             has operation_name => (
19             is => 'rwp',
20             should => Str,
21             required => 1,
22             # writer => 'overwrite_operation_name',
23             reader => 'get_operation_name', # it's not in the Interface
24             );
25              
26             has start_time => (
27             is => 'ro',
28             should => PositiveOrZeroNum,
29             default => sub { epoch_floatingpoint() }
30             );
31              
32             has finish_time => (
33             is => 'rwp',
34             should => PositiveOrZeroNum,
35             predicate => 'has_finished',
36             init_arg => undef,
37             );
38              
39             has tags => (
40             is => 'rwp',
41             should => HashRef[Value],
42             handles_via => 'Hash',
43             handles => {
44             get_tags => 'all',
45             },
46             default => sub{ {} },
47             );
48              
49             has context => (
50             is => 'ro',
51             should => SpanContext,
52             reader => 'get_context',
53             # writer => '_set_context',
54             required => 1, # either from Span->get_context or SpanContext self
55             handles => {
56             get_span_id => 'span_id',
57             },
58             );
59              
60             sub overwrite_operation_name {
61 2     2 1 1037 my $self = shift;
62            
63 2 100       23 croak "Can't overwrite an operation-name on an already finished span"
64             if $self->has_finished;
65            
66 1         3 my $operation_name = shift; # or throw an exception
67            
68 1         21 $self->_set_operation_name( $operation_name );
69            
70 1         37 return $self
71             }
72              
73             sub finish {
74 35     35 1 5204 my $self = shift;
75            
76 35 100 50     148 carp "Span has already been finished" and return $self
77             if $self->has_finished;
78            
79 34   66     130 my $epoch_timestamp = shift // epoch_floatingpoint();
80            
81 34         891 $self->_set_finish_time( $epoch_timestamp );
82            
83 34 50       1190 $self->on_finish->( $self )
84             if $self->has_on_finish;
85            
86 34         85 return $self
87             }
88              
89             sub add_tag {
90 3     3 1 1202 my $self = shift;
91            
92 3 100       50 croak "Can't set a tag on an already finished span"
93             if $self->has_finished;
94            
95 2         5 my $key = shift;
96 2         3 my $value = shift;
97            
98 2         43 $self->add_tags( $key => $value );
99            
100 2         7 return $self
101             }
102              
103             sub add_tags {
104 3     3 1 757 my $self = shift;
105            
106 3 50       24 croak "Can't set a tag on an already finished span"
107             if $self->has_finished;
108            
109 3         12 my %tags = @_;
110 3         65 $self->_set_tags(
111             { $self->get_tags, %tags }
112             );
113            
114 3         526 return $self
115             }
116              
117             sub log_data {
118 2     2 1 2147 my $self = shift;
119            
120 2 100       28 croak "Can't log any more data on an already finished span"
121             if $self->has_finished;
122            
123 1         6 my %log_data = @_;
124            
125             # ... # shall we just use Log::Any ?
126            
127 1         6 return $self
128             }
129              
130             sub add_baggage_item {
131 2     2 1 1500 my $self = shift;
132            
133 2 100       23 croak "Can't set baggage-items on an already finished span"
134             if $self->has_finished;
135            
136 1         2 my $key = shift;
137 1         3 my $value = shift;
138            
139 1         22 $self->add_baggage_items( $key => $value );
140            
141 1         6 return $self
142             }
143              
144             sub add_baggage_items {
145 3     3 1 2033 my $self = shift;
146            
147 3 100       26 croak "Can't set baggage-items on an already finished span"
148             if $self->has_finished;
149            
150 2         9 my %items = @_;
151            
152 2         42 my $new_context = $self->get_context()->with_baggage_items( %items );
153 2         25 $self->_set_context( $new_context );
154            
155 2         8 return $self
156             }
157              
158             sub get_baggage_item {
159 2     2 1 2580 my $self = shift;
160 2         4 my $key = shift;
161            
162 2         45 return $self->get_context()->get_baggage_item( $key )
163             }
164              
165             sub get_baggage_items {
166 1     1 1 13507 my $self = shift;
167            
168 1         23 return $self->get_context()->get_baggage_items
169             }
170              
171             sub duration {
172 4     4 1 3595 my $self = shift;
173            
174             my $start_time = $self->{ start_time }
175 4 100 50     44 or croak
176             "Span has not been started: ['"
177             .
178             ( $self->get_operation_name || "'undef'" )
179             .
180             "'] ... how did you do that ?";
181             my $finish_time = $self->{ finish_time }
182 3 100 50     32 or croak
183             "Span has not been finished: ['"
184             .
185             ( $self->get_operation_name || "'undef'" )
186             .
187             "'] ... yet!";
188            
189 2         15 return $finish_time - $start_time
190             }
191              
192             protected_has child_of => (
193             is => 'ro',
194             should => Span | SpanContext,
195             required => 0,
196             );
197             #
198             # this is just non of your business, and will get depricated as soon as there is
199             # references
200              
201 3     3   101 sub _get_child_of { $_[0]->child_of }
202             #
203             # so this can be swapped for something more clever once using references
204              
205             sub get_parent_span_id {
206 3     3 1 3384 my $self = shift;
207            
208 3         10 my $child_of = $self->_get_child_of;
209            
210 3 100       188 return unless defined $child_of;
211            
212 2 100       40 return $child_of->span_id
213             if is_SpanContext($child_of);
214            
215 1 50       33 return $child_of->get_context->span_id
216             if is_Span($child_of);
217            
218 0         0 croak "No 'parent span_id' for 'child_of' attribute [$child_of]"
219             #
220             # execution should never end up here
221            
222             }
223             #
224             # This may not be the right way to implement it, for the `child_of` attribute
225             # may not be such a good idea, maybe it should use references, but not sure how
226             # those are used
227              
228              
229              
230 0     0 1 0 sub is_root_span { ! shift->get_parent_span_id() }
231              
232             # _set_context
233             #
234             # you really shouldn't change the context yourself, only on instantiation
235             #
236             sub _set_context {
237 2     2   4 my $self = shift;
238            
239 2 50       8 croak "Can't set context on an already finished span"
240             if $self->has_finished;
241            
242 2 50       7 my $context = shift or die "Missing context";
243            
244 2         5 $self->{ context } = $context;
245            
246 2         3 return $self
247             }
248              
249             has on_finish => (
250             is => 'ro',
251             should => Maybe[CodeRef],
252             predicate => 1,
253             );
254              
255             sub DEMOLISH {
256 34     34 0 45180 my $self = shift;
257 34         85 my $in_global_destruction = shift;
258            
259 34 100       229 return if $self->has_finished;
260            
261             # carp "Span not programmatically finished before being demolished";
262            
263 28 50       599 $self->finish( )
264             unless $in_global_destruction;
265            
266             return
267 28         475 }
268              
269             sub epoch_floatingpoint {
270 53     53 1 455 return time()
271             }
272             #
273             # well, this is a bit off a silly idea:
274             # some implentations may want nano-second accuracy, but floating point
275             # computations using 64bits (IEEE) are only having 16 digits in the mantissa.
276             # The number of nano-seconds since epoch is 19 digits that barely fits in a
277             # signed 64 bit integer.
278              
279              
280              
281             BEGIN {
282             # use Role::Tiny::With;
283 16     16   28426 with 'OpenTracing::Interface::Span'
284             }
285              
286              
287              
288             1;