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.0';
4              
5              
6              
7 16     16   1976409 use Moo::Role;
  16         17276  
  16         100  
8 16     16   12321 use MooX::HandlesVia;
  16         12975  
  16         105  
9 16     16   8788 use MooX::ProtectedAttributes;
  16         11928  
  16         105  
10 16     16   7060 use MooX::Should;
  16         45415  
  16         105  
11              
12 16     16   1526 use Carp;
  16         34  
  16         889  
13 16     16   5879 use OpenTracing::Types qw/:types :is/;
  16         772549  
  16         125  
14 16     16   38758 use Time::HiRes qw/time/;
  16         40  
  16         197  
15 16     16   10395 use Types::Standard qw/CodeRef HashRef Maybe Num Object Str Value/;
  16         908005  
  16         168  
16 16     16   61957 use Types::Common::Numeric qw/PositiveOrZeroNum/;
  16         335969  
  16         155  
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 1170 my $self = shift;
62            
63 2 100       27 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         20 $self->_set_operation_name( $operation_name );
69            
70 1         36 return $self
71             }
72              
73             sub finish {
74 35     35 1 6576 my $self = shift;
75            
76 35 100 50     176 carp "Span has already been finished" and return $self
77             if $self->has_finished;
78            
79 34   66     122 my $epoch_timestamp = shift // epoch_floatingpoint();
80            
81 34         886 $self->_set_finish_time( $epoch_timestamp );
82            
83 34 50       1118 $self->on_finish->( $self )
84             if $self->has_on_finish;
85            
86 34         91 return $self
87             }
88              
89             sub add_tag {
90 3     3 1 1242 my $self = shift;
91            
92 3 100       30 croak "Can't set a tag on an already finished span"
93             if $self->has_finished;
94            
95 2         4 my $key = shift;
96 2         4 my $value = shift;
97            
98 2         40 $self->add_tags( $key => $value );
99            
100 2         5 return $self
101             }
102              
103             sub add_tags {
104 3     3 1 727 my $self = shift;
105            
106 3 50       12 croak "Can't set a tag on an already finished span"
107             if $self->has_finished;
108            
109 3         11 my %tags = @_;
110 3         55 $self->_set_tags(
111             { $self->get_tags, %tags }
112             );
113            
114 3         515 return $self
115             }
116              
117             sub log_data {
118 2     2 1 2186 my $self = shift;
119            
120 2 100       23 croak "Can't log any more data on an already finished span"
121             if $self->has_finished;
122            
123 1         5 my %log_data = @_;
124            
125             # ... # shall we just use Log::Any ?
126            
127 1         5 return $self
128             }
129              
130             sub add_baggage_item {
131 2     2 1 1598 my $self = shift;
132            
133 2 100       26 croak "Can't set baggage-items on an already finished span"
134             if $self->has_finished;
135            
136 1         4 my $key = shift;
137 1         2 my $value = shift;
138            
139 1         22 $self->add_baggage_items( $key => $value );
140            
141 1         5 return $self
142             }
143              
144             sub add_baggage_items {
145 3     3 1 1962 my $self = shift;
146            
147 3 100       25 croak "Can't set baggage-items on an already finished span"
148             if $self->has_finished;
149            
150 2         8 my %items = @_;
151            
152 2         38 my $new_context = $self->get_context()->with_baggage_items( %items );
153 2         22 $self->_set_context( $new_context );
154            
155 2         6 return $self
156             }
157              
158             sub get_baggage_item {
159 2     2 1 2511 my $self = shift;
160 2         5 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 13175 my $self = shift;
167            
168 1         20 return $self->get_context()->get_baggage_items
169             }
170              
171             sub duration {
172 4     4 1 4449 my $self = shift;
173            
174             my $start_time = $self->{ start_time }
175 4 100 50     57 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     25 or croak
183             "Span has not been finished: ['"
184             .
185             ( $self->get_operation_name || "'undef'" )
186             .
187             "'] ... yet!";
188            
189 2         16 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   80 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 4009 my $self = shift;
207            
208 3         8 my $child_of = $self->_get_child_of;
209            
210 3 100       204 return unless defined $child_of;
211            
212 2 100       37 return $child_of->span_id
213             if is_SpanContext($child_of);
214            
215 1 50       31 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   5 my $self = shift;
238            
239 2 50       9 croak "Can't set context on an already finished span"
240             if $self->has_finished;
241            
242 2 50       6 my $context = shift or die "Missing context";
243            
244 2         3 $self->{ context } = $context;
245            
246 2         4 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 47241 my $self = shift;
257 34         75 my $in_global_destruction = shift;
258            
259 34 100       220 return if $self->has_finished;
260            
261             # carp "Span not programmatically finished before being demolished";
262            
263 28 50       575 $self->finish( )
264             unless $in_global_destruction;
265            
266             return
267 28         474 }
268              
269             sub epoch_floatingpoint {
270 53     53 1 429 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   27695 with 'OpenTracing::Interface::Span'
284             }
285              
286              
287              
288             1;