Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 26d56c0

Browse files
authored
SDK Tracer treats invalid span parent like null (open-telemetry#233, open-telemetry#235)
The SDK tracer will now create spans with invalid parents as brand new spans, similar to not having a parent at all. Adding this behavior to the Tracer ensures that integrations do not have to handle invalid span contexts in their own code, and ensures that behavior is consistent with w3c tracecontext (which specifies invalid results should be handled by creating new spans). Setting the parent to none on spans if the parent context is invalid, reducing logic to handle that situation in downstream processing like exporters.
1 parent 5c89850 commit 26d56c0

File tree

2 files changed

+41
-23
lines changed

2 files changed

+41
-23
lines changed

opentelemetry-sdk/src/opentelemetry/sdk/trace/__init__.py

Lines changed: 27 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -376,30 +376,33 @@ def create_span(
376376
as a child of the current span in this tracer's context, or as a root
377377
span if no current span exists.
378378
"""
379+
span_id = generate_span_id()
379380

380381
if parent is Tracer.CURRENT_SPAN:
381382
parent = self.get_current_span()
382383

383-
if parent is None:
384-
parent_context = None
385-
new_span_context = trace_api.SpanContext(
386-
generate_trace_id(), generate_span_id()
387-
)
384+
parent_context = parent
385+
if isinstance(parent_context, trace_api.Span):
386+
parent_context = parent.get_context()
387+
388+
if parent_context is not None and not isinstance(
389+
parent_context, trace_api.SpanContext
390+
):
391+
raise TypeError
392+
393+
if parent_context is None or not parent_context.is_valid():
394+
parent = parent_context = None
395+
trace_id = generate_trace_id()
396+
trace_options = None
397+
trace_state = None
388398
else:
389-
if isinstance(parent, trace_api.Span):
390-
parent_context = parent.get_context()
391-
elif isinstance(parent, trace_api.SpanContext):
392-
parent_context = parent
393-
else:
394-
# TODO: error handling
395-
raise TypeError
396-
397-
new_span_context = trace_api.SpanContext(
398-
parent_context.trace_id,
399-
generate_span_id(),
400-
parent_context.trace_options,
401-
parent_context.trace_state,
402-
)
399+
trace_id = parent_context.trace_id
400+
trace_options = parent_context.trace_options
401+
trace_state = parent_context.trace_state
402+
403+
context = trace_api.SpanContext(
404+
trace_id, span_id, trace_options, trace_state
405+
)
403406

404407
# The sampler decides whether to create a real or no-op span at the
405408
# time of span creation. No-op spans do not record events, and are not
@@ -408,23 +411,24 @@ def create_span(
408411
# to include information about the sampling decision.
409412
sampling_decision = self.sampler.should_sample(
410413
parent_context,
411-
new_span_context.trace_id,
412-
new_span_context.span_id,
414+
context.trace_id,
415+
context.span_id,
413416
name,
414417
{}, # TODO: links
415418
)
416419

417420
if sampling_decision.sampled:
418421
return Span(
419422
name=name,
420-
context=new_span_context,
423+
context=context,
421424
parent=parent,
422425
sampler=self.sampler,
423426
attributes=sampling_decision.attributes,
424427
span_processor=self._active_span_processor,
425428
kind=kind,
426429
)
427-
return trace_api.DefaultSpan(context=new_span_context)
430+
431+
return trace_api.DefaultSpan(context=context)
428432

429433
@contextmanager
430434
def use_span(

opentelemetry-sdk/tests/trace/test_trace.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,20 @@ def test_sampler_no_sampling(self):
5151

5252

5353
class TestSpanCreation(unittest.TestCase):
54+
def test_create_span_invalid_spancontext(self):
55+
"""If an invalid span context is passed as the parent, the created
56+
span should use a new span id.
57+
58+
Invalid span contexts should also not be added as a parent. This
59+
eliminates redundant error handling logic in exporters.
60+
"""
61+
tracer = trace.Tracer("test_create_span_invalid_spancontext")
62+
new_span = tracer.create_span(
63+
"root", parent=trace_api.INVALID_SPAN_CONTEXT
64+
)
65+
self.assertTrue(new_span.context.is_valid())
66+
self.assertIsNone(new_span.parent)
67+
5468
def test_start_span_implicit(self):
5569
tracer = trace.Tracer("test_start_span_implicit")
5670

0 commit comments

Comments
 (0)