diff --git a/src/instana/tracer.py b/src/instana/tracer.py index 266f2fd7..0c2c1919 100644 --- a/src/instana/tracer.py +++ b/src/instana/tracer.py @@ -29,7 +29,7 @@ from instana.sampling import InstanaSampler, Sampler from instana.span.span import InstanaSpan, get_current_span from instana.span_context import SpanContext -from instana.util.ids import generate_id, hex_id, hex_id_limited +from instana.util.ids import generate_id, hex_id, internal_id_limited if TYPE_CHECKING: from opentelemetry.trace import Span @@ -123,15 +123,18 @@ def start_span( if parent_context and not isinstance(parent_context, SpanContext): if parent_context.is_valid: logger.debug("Converting non-Instana parent context to Instana SpanContext") - hex_tid = hex_id(parent_context.trace_id) + # OTel trace IDs are 128-bit ints; Instana uses 64-bit internally. + # internal_id_limited() masks to the lower 64 bits for trace_id, + # while the full 128-bit value is preserved as a hex string in + # long_trace_id for W3C traceparent propagation. parent_context = SpanContext( - trace_id=int(hex_id_limited(parent_context.trace_id), 16) if len(hex_tid) > 16 else parent_context.trace_id, + trace_id=internal_id_limited(parent_context.trace_id), span_id=parent_context.span_id, is_remote=parent_context.is_remote, trace_flags=parent_context.trace_flags, trace_state=parent_context.trace_state, trace_parent=None, - long_trace_id=hex_tid if len(hex_tid) > 16 else None, + long_trace_id=hex_id(parent_context.trace_id), ) else: logger.debug("Non-Instana parent context is invalid, resetting to None") diff --git a/src/instana/util/ids.py b/src/instana/util/ids.py index f3fba11b..fa895c9a 100644 --- a/src/instana/util/ids.py +++ b/src/instana/util/ids.py @@ -164,10 +164,11 @@ def internal_id(id: Union[int, str]) -> int: def internal_id_limited(id: Union[int, str]) -> int: """ Returns a valid id to be used internally. Handles both str and int types. - Note: Limits the hex string to 16 chars before conversion. + Note: Limits the value to the lower 64 bits. """ if isinstance(id, int): - return id + # Mask to the lower 64 bits. + return id & 0xFFFFFFFFFFFFFFFF length = len(id) diff --git a/tests/test_tracer.py b/tests/test_tracer.py index 3c91e42b..68dd6331 100644 --- a/tests/test_tracer.py +++ b/tests/test_tracer.py @@ -268,9 +268,10 @@ def test_tracer_kind_propagation_to_readable_span( # Parametrized tests: start_span with different context / parent-span types # --------------------------------------------------------------------------- -# A valid 128-bit and 64-bit OTel trace_id and span_id +# A valid 128-bit OTel trace_id; a 64-bit value for Instana-internal use; and a span_id. +# Note: real OTel trace IDs are always 128-bit per the W3C Trace Context spec. _OTEL_128BIT_TRACE_ID = 0x1234567890ABCDEF18BED7B8D2E72F6B -_OTEL_64BIT_TRACE_ID = 0x18BED7B8D2E72F6B +_OTEL_64BIT_TRACE_ID = 0x18BED7B8D2E72F6B # used for Instana SpanContext fixtures only _OTEL_SPAN_ID = 0x5FB3484FB90A5BAD @@ -326,15 +327,6 @@ def _make_instana_context(trace_id: int, span_id: int) -> Context: False, # NOT a root span – parent_id must be set id="otel_span_context_128bit_parent", ), - # --- OTel SpanContext parent with 64-bit trace ID (valid) --- - # The tracer must convert it to an Instana SpanContext and use its trace_id directly. - pytest.param( - lambda: _make_otel_context(_OTEL_64BIT_TRACE_ID, _OTEL_SPAN_ID, is_valid=True), - _OTEL_64BIT_TRACE_ID, - None, - False, # NOT a root span – parent_id must be set - id="otel_span_context_64bit_parent", - ), # --- OTel SpanContext parent (invalid, i.e. trace_id=0, span_id=0) --- # The tracer must ignore it and create a new root span. pytest.param(