Skip to content

Commit 1112792

Browse files
Add proper length zero padding to hex strings of traceId, spanId, parentId sent on the wire (open-telemetry#908)
1 parent 8c4fca5 commit 1112792

File tree

3 files changed

+74
-5
lines changed

3 files changed

+74
-5
lines changed

exporter/opentelemetry-exporter-zipkin/CHANGELOG.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44

55
- Change package name to opentelemetry-exporter-zipkin
66
([#953](https://github.com/open-telemetry/opentelemetry-python/pull/953))
7+
- Add proper length zero padding to hex strings of traceId, spanId, parentId sent on the wire, for compatibility with jaeger-collector
8+
([#908](https://github.com/open-telemetry/opentelemetry-python/pull/908))
79

810
## 0.8b0
911

@@ -23,4 +25,4 @@ Released 2020-05-12
2325

2426
Released 2020-02-21
2527

26-
- Initial release
28+
- Initial release

exporter/opentelemetry-exporter-zipkin/src/opentelemetry/exporter/zipkin/__init__.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -168,8 +168,9 @@ def _translate_to_zipkin(self, spans: Sequence[Span]):
168168
duration_mus = _nsec_to_usec_round(span.end_time - span.start_time)
169169

170170
zipkin_span = {
171-
"traceId": format(trace_id, "x"),
172-
"id": format(span_id, "x"),
171+
# Ensure left-zero-padding of traceId, spanId, parentId
172+
"traceId": format(trace_id, "032x"),
173+
"id": format(span_id, "016x"),
173174
"name": span.name,
174175
"timestamp": start_timestamp_mus,
175176
"duration": duration_mus,
@@ -184,10 +185,10 @@ def _translate_to_zipkin(self, spans: Sequence[Span]):
184185

185186
if isinstance(span.parent, Span):
186187
zipkin_span["parentId"] = format(
187-
span.parent.get_context().span_id, "x"
188+
span.parent.get_context().span_id, "016x"
188189
)
189190
elif isinstance(span.parent, SpanContext):
190-
zipkin_span["parentId"] = format(span.parent.span_id, "x")
191+
zipkin_span["parentId"] = format(span.parent.span_id, "016x")
191192

192193
zipkin_spans.append(zipkin_span)
193194
return zipkin_spans

exporter/opentelemetry-exporter-zipkin/tests/test_zipkin_exporter.py

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -264,6 +264,72 @@ def test_export(self):
264264
headers={"Content-Type": "application/json"},
265265
)
266266

267+
# pylint: disable=too-many-locals
268+
def test_zero_padding(self):
269+
"""test that hex ids starting with 0
270+
are properly padded to 16 or 32 hex chars
271+
when exported
272+
"""
273+
274+
span_names = "testZeroes"
275+
trace_id = 0x0E0C63257DE34C926F9EFCD03927272E
276+
span_id = 0x04BF92DEEFC58C92
277+
parent_id = 0x0AAAAAAAAAAAAAAA
278+
279+
start_time = 683647322 * 10 ** 9 # in ns
280+
duration = 50 * 10 ** 6
281+
end_time = start_time + duration
282+
283+
span_context = trace_api.SpanContext(
284+
trace_id,
285+
span_id,
286+
is_remote=False,
287+
trace_flags=TraceFlags(TraceFlags.SAMPLED),
288+
)
289+
parent_context = trace_api.SpanContext(
290+
trace_id, parent_id, is_remote=False
291+
)
292+
293+
otel_span = trace.Span(
294+
name=span_names[0], context=span_context, parent=parent_context,
295+
)
296+
297+
otel_span.start(start_time=start_time)
298+
otel_span.end(end_time=end_time)
299+
300+
service_name = "test-service"
301+
local_endpoint = {"serviceName": service_name, "port": 9411}
302+
303+
exporter = ZipkinSpanExporter(service_name)
304+
# Check traceId are properly lowercase 16 or 32 hex
305+
expected = [
306+
{
307+
"traceId": "0e0c63257de34c926f9efcd03927272e",
308+
"id": "04bf92deefc58c92",
309+
"name": span_names[0],
310+
"timestamp": start_time // 10 ** 3,
311+
"duration": duration // 10 ** 3,
312+
"localEndpoint": local_endpoint,
313+
"kind": None,
314+
"tags": {},
315+
"annotations": None,
316+
"debug": True,
317+
"parentId": "0aaaaaaaaaaaaaaa",
318+
}
319+
]
320+
321+
mock_post = MagicMock()
322+
with patch("requests.post", mock_post):
323+
mock_post.return_value = MockResponse(200)
324+
status = exporter.export([otel_span])
325+
self.assertEqual(SpanExportResult.SUCCESS, status)
326+
327+
mock_post.assert_called_with(
328+
url="http://localhost:9411/api/v2/spans",
329+
data=json.dumps(expected),
330+
headers={"Content-Type": "application/json"},
331+
)
332+
267333
@patch("requests.post")
268334
def test_invalid_response(self, mock_post):
269335
mock_post.return_value = MockResponse(404)

0 commit comments

Comments
 (0)