13
13
# limitations under the License.
14
14
15
15
import logging
16
- from collections import abc
17
- from typing import Any , List , Optional , Sequence
18
-
16
+ from collections import defaultdict
17
+ from typing import List , Optional , Sequence
18
+
19
+ from opentelemetry .exporter .otlp .proto .common import (
20
+ _encode_trace_id ,
21
+ _encode_span_id ,
22
+ _encode_key_value ,
23
+ _encode_instrumentation_scope ,
24
+ )
19
25
from opentelemetry .proto .collector .trace .v1 .trace_service_pb2 import (
20
26
ExportTraceServiceRequest as PB2ExportTraceServiceRequest ,
21
27
)
22
- from opentelemetry .proto .common .v1 .common_pb2 import AnyValue as PB2AnyValue
23
- from opentelemetry .proto .common .v1 .common_pb2 import (
24
- ArrayValue as PB2ArrayValue ,
25
- )
26
- from opentelemetry .proto .common .v1 .common_pb2 import (
27
- InstrumentationScope as PB2InstrumentationScope ,
28
- )
29
28
from opentelemetry .proto .common .v1 .common_pb2 import KeyValue as PB2KeyValue
30
29
from opentelemetry .proto .resource .v1 .resource_pb2 import (
31
30
Resource as PB2Resource ,
38
37
)
39
38
from opentelemetry .proto .trace .v1 .trace_pb2 import Span as PB2SPan
40
39
from opentelemetry .proto .trace .v1 .trace_pb2 import Status as PB2Status
41
- from opentelemetry .sdk .trace import Event
42
- from opentelemetry .sdk .util .instrumentation import InstrumentationScope
40
+ from opentelemetry .sdk .trace import Event , ReadableSpan
43
41
from opentelemetry .sdk .trace import Resource
44
- from opentelemetry .sdk .trace import Span as SDKSpan
45
42
from opentelemetry .trace import Link
46
43
from opentelemetry .trace import SpanKind
47
44
from opentelemetry .trace .span import SpanContext , TraceState , Status
59
56
_logger = logging .getLogger (__name__ )
60
57
61
58
62
- class _ProtobufEncoder :
63
- @classmethod
64
- def serialize (cls , sdk_spans : Sequence [SDKSpan ]) -> str :
65
- return cls .encode (sdk_spans ).SerializeToString ()
66
-
67
- @staticmethod
68
- def encode (sdk_spans : Sequence [SDKSpan ]) -> PB2ExportTraceServiceRequest :
69
- return PB2ExportTraceServiceRequest (
70
- resource_spans = _encode_resource_spans (sdk_spans )
71
- )
59
+ def encode_spans (
60
+ sdk_spans : Sequence [ReadableSpan ],
61
+ ) -> PB2ExportTraceServiceRequest :
62
+ return PB2ExportTraceServiceRequest (
63
+ resource_spans = _encode_resource_spans (sdk_spans )
64
+ )
72
65
73
66
74
67
def _encode_resource_spans (
75
- sdk_spans : Sequence [SDKSpan ],
68
+ sdk_spans : Sequence [ReadableSpan ],
76
69
) -> List [PB2ResourceSpans ]:
77
70
# We need to inspect the spans and group + structure them as:
78
71
#
@@ -85,25 +78,14 @@ def _encode_resource_spans(
85
78
#
86
79
# Second loop encodes the data into Protobuf format.
87
80
#
88
- sdk_resource_spans = {}
81
+ sdk_resource_spans = defaultdict ( lambda : defaultdict ( list ))
89
82
90
83
for sdk_span in sdk_spans :
91
84
sdk_resource = sdk_span .resource
92
85
sdk_instrumentation = sdk_span .instrumentation_scope or None
93
86
pb2_span = _encode_span (sdk_span )
94
87
95
- if sdk_resource not in sdk_resource_spans .keys ():
96
- sdk_resource_spans [sdk_resource ] = {
97
- sdk_instrumentation : [pb2_span ]
98
- }
99
- elif (
100
- sdk_instrumentation not in sdk_resource_spans [sdk_resource ].keys ()
101
- ):
102
- sdk_resource_spans [sdk_resource ][sdk_instrumentation ] = [pb2_span ]
103
- else :
104
- sdk_resource_spans [sdk_resource ][sdk_instrumentation ].append (
105
- pb2_span
106
- )
88
+ sdk_resource_spans [sdk_resource ][sdk_instrumentation ].append (pb2_span )
107
89
108
90
pb2_resource_spans = []
109
91
@@ -126,7 +108,7 @@ def _encode_resource_spans(
126
108
return pb2_resource_spans
127
109
128
110
129
- def _encode_span (sdk_span : SDKSpan ) -> PB2SPan :
111
+ def _encode_span (sdk_span : ReadableSpan ) -> PB2SPan :
130
112
span_context = sdk_span .get_span_context ()
131
113
return PB2SPan (
132
114
trace_id = _encode_trace_id (span_context .trace_id ),
@@ -141,6 +123,9 @@ def _encode_span(sdk_span: SDKSpan) -> PB2SPan:
141
123
events = _encode_events (sdk_span .events ),
142
124
links = _encode_links (sdk_span .links ),
143
125
status = _encode_status (sdk_span .status ),
126
+ dropped_attributes_count = sdk_span .dropped_attributes ,
127
+ dropped_events_count = sdk_span .dropped_events ,
128
+ dropped_links_count = sdk_span .dropped_links ,
144
129
)
145
130
146
131
@@ -154,6 +139,7 @@ def _encode_events(
154
139
encoded_event = PB2SPan .Event (
155
140
name = event .name ,
156
141
time_unix_nano = event .timestamp ,
142
+ dropped_attributes_count = event .attributes .dropped ,
157
143
)
158
144
for key , value in event .attributes .items ():
159
145
try :
@@ -167,14 +153,15 @@ def _encode_events(
167
153
return pb2_events
168
154
169
155
170
- def _encode_links (links : List [Link ]) -> List [PB2SPan .Link ]:
156
+ def _encode_links (links : Sequence [Link ]) -> Sequence [PB2SPan .Link ]:
171
157
pb2_links = None
172
158
if links :
173
159
pb2_links = []
174
160
for link in links :
175
161
encoded_link = PB2SPan .Link (
176
162
trace_id = _encode_trace_id (link .context .trace_id ),
177
163
span_id = _encode_span_id (link .context .span_id ),
164
+ dropped_attributes_count = link .attributes .dropped ,
178
165
)
179
166
for key , value in link .attributes .items ():
180
167
try :
@@ -208,11 +195,9 @@ def _encode_trace_state(trace_state: TraceState) -> Optional[str]:
208
195
209
196
210
197
def _encode_parent_id (context : Optional [SpanContext ]) -> Optional [bytes ]:
211
- if isinstance (context , SpanContext ):
212
- encoded_parent_id = _encode_span_id (context .span_id )
213
- else :
214
- encoded_parent_id = None
215
- return encoded_parent_id
198
+ if context :
199
+ return _encode_span_id (context .span_id )
200
+ return None
216
201
217
202
218
203
def _encode_attributes (
@@ -239,50 +224,3 @@ def _encode_resource(resource: Resource) -> PB2Resource:
239
224
except Exception as error : # pylint: disable=broad-except
240
225
_logger .exception (error )
241
226
return pb2_resource
242
-
243
-
244
- def _encode_instrumentation_scope (
245
- instrumentation_scope : InstrumentationScope ,
246
- ) -> PB2InstrumentationScope :
247
- if instrumentation_scope is None :
248
- pb2_instrumentation_scope = PB2InstrumentationScope ()
249
- else :
250
- pb2_instrumentation_scope = PB2InstrumentationScope (
251
- name = instrumentation_scope .name ,
252
- version = instrumentation_scope .version ,
253
- )
254
- return pb2_instrumentation_scope
255
-
256
-
257
- def _encode_value (value : Any ) -> PB2AnyValue :
258
- if isinstance (value , bool ):
259
- any_value = PB2AnyValue (bool_value = value )
260
- elif isinstance (value , str ):
261
- any_value = PB2AnyValue (string_value = value )
262
- elif isinstance (value , int ):
263
- any_value = PB2AnyValue (int_value = value )
264
- elif isinstance (value , float ):
265
- any_value = PB2AnyValue (double_value = value )
266
- elif isinstance (value , abc .Sequence ):
267
- any_value = PB2AnyValue (
268
- array_value = PB2ArrayValue (values = [_encode_value (v ) for v in value ])
269
- )
270
- # tracing specs currently does not support Mapping type attributes.
271
- # elif isinstance(value, abc.Mapping):
272
- # pass
273
- else :
274
- raise Exception (f"Invalid type { type (value )} of value { value } " )
275
- return any_value
276
-
277
-
278
- def _encode_key_value (key : str , value : Any ) -> PB2KeyValue :
279
- any_value = _encode_value (value )
280
- return PB2KeyValue (key = key , value = any_value )
281
-
282
-
283
- def _encode_span_id (span_id : int ) -> bytes :
284
- return span_id .to_bytes (length = 8 , byteorder = "big" , signed = False )
285
-
286
-
287
- def _encode_trace_id (trace_id : int ) -> bytes :
288
- return trace_id .to_bytes (length = 16 , byteorder = "big" , signed = False )
0 commit comments