File Coverage

blib/lib/OpenTracing/Role/Span.pm
Criterion Covered Total %
statement 92 93 98.9
branch 28 34 82.3
condition 5 9 55.5
subroutine 25 25 100.0
pod 12 13 92.3
total 162 174 93.1


line stmt bran cond sub pod time code
1             package OpenTracing::Role::Span;
2              
3             our $VERSION = 'v0.85.0';
4              
5              
6              
7 16     16   1861601 use Moo::Role;
  16         16695  
  16         102  
8 16     16   11742 use MooX::HandlesVia;
  16         12569  
  16         106  
9 16     16   9484 use MooX::ProtectedAttributes;
  16         12060  
  16         97  
10 16     16   6322 use MooX::Should;
  16         42398  
  16         99  
11              
12 16     16   1634 use Carp;
  16         36  
  16         887  
13 16     16   5412 use OpenTracing::Types qw/:types :is/;
  16         661444  
  16         156  
14 16     16   31301 use Time::HiRes qw/time/;
  16         41  
  16         156  
15 16     16   9876 use Types::Standard qw/CodeRef HashRef Maybe Num Object Str Value/;
  16         770984  
  16         212  
16 16     16   32374 use Types::Common::Numeric qw/PositiveOrZeroNum/;
  16         273363  
  16         146  
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 1081 my $self = shift;
62            
63 2 100       26 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         33 return $self
71             }
72              
73             sub finish {
74 35     35 1 5775 my $self = shift;
75            
76 35 100 50     147 carp "Span has already been finished" and return $self
77             if $self->has_finished;
78            
79 34   66     120 my $epoch_timestamp = shift // epoch_floatingpoint();
80            
81 34         903 $self->_set_finish_time( $epoch_timestamp );
82            
83 34 50       1036 $self->on_finish->( $self )
84             if $self->has_on_finish;
85            
86 34         78 return $self
87             }
88              
89             sub add_tag {
90 3     3 1 1214 my $self = shift;
91            
92 3 100       29 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         40 $self->add_tags( $key => $value );
99            
100 2         5 return $self
101             }
102              
103             sub add_tags {
104 3     3 1 681 my $self = shift;
105            
106 3 50       15 croak "Can't set a tag on an already finished span"
107             if $self->has_finished;
108            
109 3         9 my %tags = @_;
110 3         71 $self->_set_tags(
111             { $self->get_tags, %tags }
112             );
113            
114 3         545 return $self
115             }
116              
117             sub log_data {
118 2     2 1 1907 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         4 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 1732 my $self = shift;
132            
133 2 100       24 croak "Can't set baggage-items on an already finished span"
134             if $self->has_finished;
135            
136 1         3 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 2041 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         7 my %items = @_;
151            
152 2         40 my $new_context = $self->get_context()->with_baggage_items( %items );
153 2         20 $self->_set_context( $new_context );
154            
155 2         7 return $self
156             }
157              
158             sub get_baggage_item {
159 2     2 1 2888 my $self = shift;
160 2         5 my $key = shift;
161            
162 2         44 return $self->get_context()->get_baggage_item( $key )
163             }
164              
165             sub get_baggage_items {
166 1     1 1 12853 my $self = shift;
167            
168 1         21 return $self->get_context()->get_baggage_items
169             }
170              
171             sub duration {
172 4     4 1 4139 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     23 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   65 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 3185 my $self = shift;
207            
208 3         8 my $child_of = $self->_get_child_of;
209            
210 3 100       181 return unless defined $child_of;
211            
212 2 100       31 return $child_of->span_id
213             if is_SpanContext($child_of);
214            
215 1 50       26 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             # _set_context
231             #
232             # you really shouldn't change the context yourself, only on instantiation
233             #
234             sub _set_context {
235 2     2   5 my $self = shift;
236            
237 2 50       9 croak "Can't set context on an already finished span"
238             if $self->has_finished;
239            
240 2 50       7 my $context = shift or die "Missing context";
241            
242 2         5 $self->{ context } = $context;
243            
244 2         3 return $self
245             }
246              
247             has on_finish => (
248             is => 'ro',
249             should => Maybe[CodeRef],
250             predicate => 1,
251             );
252              
253             sub DEMOLISH {
254 34     34 0 44427 my $self = shift;
255 34         72 my $in_global_destruction = shift;
256            
257 34 100       210 return if $self->has_finished;
258            
259             # carp "Span not programmatically finished before being demolished";
260            
261 28 50       565 $self->finish( )
262             unless $in_global_destruction;
263            
264             return
265 28         442 }
266              
267             sub epoch_floatingpoint {
268 53     53 1 400 return time()
269             }
270             #
271             # well, this is a bit off a silly idea:
272             # some implentations may want nano-second accuracy, but floating point
273             # computations using 64bits (IEEE) are only having 16 digits in the mantissa.
274             # The number of nano-seconds since epoch is 19 digits that barely fits in a
275             # signed 64 bit integer.
276              
277              
278              
279             BEGIN {
280             # use Role::Tiny::With;
281 16     16   22821 with 'OpenTracing::Interface::Span'
282             }
283              
284              
285              
286             1;