Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 7 additions & 4 deletions src/instana/tracer.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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")
Expand Down
5 changes: 3 additions & 2 deletions src/instana/util/ids.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand Down
14 changes: 3 additions & 11 deletions tests/test_tracer.py
Original file line number Diff line number Diff line change
Expand Up @@ -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


Expand Down Expand Up @@ -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(
Expand Down
Loading