File Coverage

blib/lib/OpenTelemetry/Exporter/OTLP/Encoder/JSON.pm
Criterion Covered Total %
statement 122 139 87.7
branch 8 12 66.6
condition 6 9 66.6
subroutine 20 23 86.9
pod 3 17 17.6
total 159 200 79.5


line stmt bran cond sub pod time code
1 3     3   185214 use Object::Pad ':experimental(init_expr)';
  3         15922  
  3         35  
2             # ABSTRACT: A JSON encoder for the OTLP exporter
3              
4             package OpenTelemetry::Exporter::OTLP::Encoder::JSON;
5              
6             our $VERSION = '0.021';
7              
8             class OpenTelemetry::Exporter::OTLP::Encoder::JSON {
9 3     3   3354 use JSON::MaybeXS;
  3         35018  
  3         370  
10 3     3   757 use OpenTelemetry::Constants 'HEX_INVALID_SPAN_ID';
  3         13682  
  3         119  
11 3     3   2938 use Ref::Util qw( is_hashref is_arrayref );
  3         3044  
  3         284  
12 3     3   23 use Scalar::Util 'refaddr';
  3         5  
  3         195  
13              
14 3     3   596 use isa 'OpenTelemetry::SDK::Logs::LogRecord';
  3         8534  
  3         59  
15              
16 4     4 1 7 method content_type () { 'application/json' }
  4         12  
  4         6  
  4         61  
17              
18 6     6 1 61 method serialise ($data) { encode_json $data }
  6         33  
  6         10  
  6         8  
  6         320  
19              
20 0     0 0 0 method encode_arraylist ($v) {
  0         0  
  0         0  
  0         0  
21 0         0 [ map $self->encode_anyvalue($_), @$v ]
22             }
23              
24 50     50 0 153 method encode_kvlist ($v) {
  50         74  
  50         65  
  50         55  
25             [
26             map {
27 50         172 {
28             key => $_,
29 4         13 value => $self->encode_anyvalue( $v->{$_} )
30             }
31             } keys %$v
32             ]
33             }
34              
35 12     12 0 30 method encode_anyvalue ( $v ) {
  12         17  
  12         17  
  12         13  
36 12 50       26 return { kvlistValue => { values => $self->encode_kvlist($v) } }
37             if is_hashref $v;
38              
39 12 50       25 return { arrayValue => { values => $self->encode_arraylist($v) } }
40             if is_arrayref $v;
41              
42 12 50       46 if ( my $ref = ref $v ) {
43 0         0 warn "Unsupported ref while encoding: $ref";
44 0         0 return;
45             }
46              
47             # TODO: not strings
48 12         66 return { stringValue => "$v" };
49             }
50              
51 14     14 0 25 method encode_resource ( $resource ) {
  14         45  
  14         23  
  14         17  
52             {
53 14         51 attributes => $self->encode_kvlist($resource->attributes),
54             droppedAttributesCount => $resource->dropped_attributes,
55             };
56             }
57              
58 0     0 0 0 method encode_span_event ( $event ) {
  0         0  
  0         0  
  0         0  
59             {
60 0         0 attributes => $self->encode_kvlist($event->attributes),
61             droppedAttributesCount => $event->dropped_attributes,
62             name => $event->name,
63             timeUnixNano => int $event->timestamp * 1_000_000_000,
64             };
65             }
66              
67 0     0 0 0 method encode_span_link ( $link ) {
  0         0  
  0         0  
  0         0  
68             {
69 0         0 attributes => $self->encode_kvlist($link->attributes),
70             droppedAttributesCount => $link->dropped_attributes,
71             spanId => $link->context->hex_span_id,
72             traceId => $link->context->hex_trace_id,
73             };
74             }
75              
76 10     10 0 697 method encode_span_status ( $status ) {
  10         19  
  10         16  
  10         17  
77             {
78 10         33 code => $status->code,
79             message => '' . $status->description,
80             };
81             }
82              
83 10     10 0 95 method encode_span ( $span ) {
  10         38  
  10         18  
  10         12  
84 10         40 my $data = {
85             attributes => $self->encode_kvlist($span->attributes),
86             droppedAttributesCount => $span->dropped_attributes,
87             droppedEventsCount => $span->dropped_events,
88             droppedLinksCount => $span->dropped_links,
89             endTimeUnixNano => int $span->end_timestamp * 1_000_000_000,
90             events => [ map $self->encode_span_event($_), $span->events ],
91             kind => $span->kind,
92             links => [ map $self->encode_span_link($_), $span->links ],
93             name => $span->name,
94             spanId => $span->hex_span_id,
95             startTimeUnixNano => int $span->start_timestamp * 1_000_000_000,
96             status => $self->encode_span_status($span->status),
97             traceId => $span->hex_trace_id,
98             traceState => $span->trace_state->to_string,
99             };
100              
101 10         683 my $parent = $span->hex_parent_span_id;
102 10 50       54 $data->{parentSpanId} = $parent
103             unless $parent eq HEX_INVALID_SPAN_ID;
104              
105 10         75 $data;
106             }
107              
108 8     8 0 80 method encode_log ( $log ) {
  8         14  
  8         10  
  8         49  
109 8         23 my $data = {
110             attributes => $self->encode_kvlist($log->attributes),
111             body => $self->encode_anyvalue($log->body),
112             droppedAttributesCount => $log->dropped_attributes,
113             flags => $log->trace_flags->flags,
114             observedTimeUnixNano => int $log->observed_timestamp * 1_000_000_000,
115             severityNumber => $log->severity_number,
116             severityText => $log->severity_text,
117             spanId => $log->hex_span_id,
118             traceId => $log->hex_trace_id,
119             };
120              
121 8         317 my $t = $log->timestamp;
122 8 100       27 $data->{timeUnixNano} = int $t * 1_000_000_000 if defined $t;
123              
124 8         42 $data;
125             }
126              
127 18     18 0 24 method encode_scope ( $scope ) {
  18         26  
  18         44  
  18         22  
128             {
129 18         60 attributes => $self->encode_kvlist($scope->attributes),
130             droppedAttributesCount => $scope->dropped_attributes,
131             name => $scope->name,
132             version => $scope->version,
133             };
134             }
135              
136 10     10 0 64 method encode_scope_spans ( $scope, $spans ) {
  10         18  
  10         15  
  10         27  
  10         14  
137             {
138 10         25 scope => $self->encode_scope($scope),
139             spans => [ map $self->encode_span($_), @$spans ],
140             };
141             }
142              
143 8     8 0 46 method encode_scope_logs ( $scope, $logs ) {
  8         15  
  8         13  
  8         10  
  8         10  
144             {
145 8         23 scope => $self->encode_scope($scope),
146             logRecords => [ map $self->encode_log($_), @$logs ],
147             };
148             }
149              
150 8     8 0 50 method encode_resource_spans ( $resource, $spans ) {
  8         24  
  8         14  
  8         15  
  8         13  
151 8         14 my %scopes;
152              
153 8         22 for (@$spans) {
154 10         31 my $key = refaddr $_->instrumentation_scope;
155              
156 10   50     11662 $scopes{ $key } //= [ $_->instrumentation_scope, [] ];
157 10         53 push @{ $scopes{ $key }[1] }, $_;
  10         32  
158             }
159              
160             {
161 8         36 resource => $self->encode_resource($resource),
162             scopeSpans => [ map $self->encode_scope_spans(@$_), values %scopes ],
163             schemaUrl => $resource->schema_url,
164             };
165             }
166              
167 6     6 0 42 method encode_resource_logs ( $resource, $logs ) {
  6         15  
  6         8  
  6         7  
  6         7  
168 6         9 my %scopes;
169              
170 6         12 for (@$logs) {
171 8         20 my $key = refaddr $_->instrumentation_scope;
172              
173 8   50     5836 $scopes{ $key } //= [ $_->instrumentation_scope, [] ];
174 8         38 push @{ $scopes{ $key }[1] }, $_;
  8         23  
175             }
176              
177             {
178 6         17 resource => $self->encode_resource($resource),
179             scopeLogs => [ map $self->encode_scope_logs(@$_), values %scopes ],
180             schemaUrl => $resource->schema_url,
181             };
182             }
183              
184 6     6 1 1494 method encode ( $data ) {
  6         16  
  6         14  
  6         24  
185 6         28 my ( %request, %resources );
186              
187 6         0 my $type;
188 6         18 for (@$data) {
189 18 100 66     106 $type //= isa_OpenTelemetry_SDK_Logs_LogRecord($_)
190             ? 'logs'
191             : 'spans';
192              
193 18         45 my $key = refaddr $_->resource;
194 18   100     17446 $resources{ $key } //= [ $_->resource, [] ];
195 18         87 push @{ $resources{ $key }[1] }, $_;
  18         71  
196             }
197              
198 6         12 my $encode = "encode_resource_$type";
199 6         677 $self->serialise({
200             'resource' . ucfirst $type => [
201             map $self->$encode(@$_), values %resources,
202             ]
203             });
204             }
205             }