Skip to content
Open
Show file tree
Hide file tree
Changes from 2 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
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
([#4755](https://github.com/open-telemetry/opentelemetry-python/pull/4755))
- logs: extend Logger.emit to accept separated keyword arguments
([#4737](https://github.com/open-telemetry/opentelemetry-python/pull/4737))
- otlp exporters (trace): include W3C TraceFlags (bits 0–7) in OTLP `Span.flags` alongside parent isRemote bits (8–9)
([#4761](https://github.com/open-telemetry/opentelemetry-python/pull/4761))

## Version 1.37.0/0.58b0 (2025-09-11)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -105,10 +105,14 @@ def _encode_resource_spans(
return pb2_resource_spans


def _span_flags(parent_span_context: Optional[SpanContext]) -> int:
flags = PB2SpanFlags.SPAN_FLAGS_CONTEXT_HAS_IS_REMOTE_MASK
if parent_span_context and parent_span_context.is_remote:
flags |= PB2SpanFlags.SPAN_FLAGS_CONTEXT_IS_REMOTE_MASK
def _span_flags(child_trace_flags: int, parent_span_context: Optional[SpanContext]) -> int:
# Lower 8 bits: W3C TraceFlags
flags = int(child_trace_flags) & int(PB2SpanFlags.SPAN_FLAGS_TRACE_FLAGS_MASK)
# Always indicate whether parent remote information is known
flags |= int(PB2SpanFlags.SPAN_FLAGS_CONTEXT_HAS_IS_REMOTE_MASK)
# Set remote bit when applicable
if parent_span_context and getattr(parent_span_context, "is_remote", False):
flags |= int(PB2SpanFlags.SPAN_FLAGS_CONTEXT_IS_REMOTE_MASK)
return flags


Expand All @@ -130,7 +134,7 @@ def _encode_span(sdk_span: ReadableSpan) -> PB2SPan:
dropped_attributes_count=sdk_span.dropped_attributes,
dropped_events_count=sdk_span.dropped_events,
dropped_links_count=sdk_span.dropped_links,
flags=_span_flags(sdk_span.parent),
flags=_span_flags(getattr(span_context, "trace_flags", 0), sdk_span.parent),
)


Expand Down Expand Up @@ -161,7 +165,7 @@ def _encode_links(links: Sequence[Link]) -> Sequence[PB2SPan.Link]:
span_id=_encode_span_id(link.context.span_id),
attributes=_encode_attributes(link.attributes),
dropped_attributes_count=link.dropped_attributes,
flags=_span_flags(link.context),
flags=_span_flags(getattr(link.context, "trace_flags", 0), link.context),
)
pb2_links.append(encoded_link)
return pb2_links
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@
from opentelemetry.exporter.otlp.proto.common._internal.trace_encoder import (
_SPAN_KIND_MAP,
_encode_status,
_encode_span,
_encode_links,
)
from opentelemetry.exporter.otlp.proto.common.trace_encoder import encode_spans
from opentelemetry.proto.collector.trace.v1.trace_service_pb2 import (
Expand All @@ -43,6 +45,7 @@
from opentelemetry.proto.trace.v1.trace_pb2 import ScopeSpans as PB2ScopeSpans
from opentelemetry.proto.trace.v1.trace_pb2 import Span as PB2SPan
from opentelemetry.proto.trace.v1.trace_pb2 import Status as PB2Status
from opentelemetry.proto.trace.v1.trace_pb2 import SpanFlags as PB2SpanFlags
from opentelemetry.sdk.trace import Event as SDKEvent
from opentelemetry.sdk.trace import Resource as SDKResource
from opentelemetry.sdk.trace import SpanContext as SDKSpanContext
Expand Down Expand Up @@ -291,14 +294,14 @@ def get_exhaustive_test_spans(
),
),
],
flags=0x100,
flags=0x101,
)
],
status=PB2Status(
code=SDKStatusCode.ERROR.value,
message="Example description",
),
flags=0x300,
flags=0x301,
)
],
),
Expand Down Expand Up @@ -501,3 +504,51 @@ def test_encode_status_code_translations(self):
code=SDKStatusCode.ERROR.value,
),
)


class TestSpanFlagsEncoding(unittest.TestCase):
def test_span_flags_root_unsampled(self):
sc = SDKSpanContext(0x1, 0x2, is_remote=False, trace_flags=0x00)
span = SDKSpan(name="root", context=sc, parent=None)
span.start(); span.end()
pb = _encode_span(span)
assert (pb.flags & PB2SpanFlags.SPAN_FLAGS_TRACE_FLAGS_MASK) == 0x00
assert (pb.flags & PB2SpanFlags.SPAN_FLAGS_CONTEXT_HAS_IS_REMOTE_MASK) != 0
assert (pb.flags & PB2SpanFlags.SPAN_FLAGS_CONTEXT_IS_REMOTE_MASK) == 0
assert (pb.flags & ~0x3FF) == 0

def test_span_flags_root_sampled(self):
sc = SDKSpanContext(0x1, 0x2, is_remote=False, trace_flags=0x01)
span = SDKSpan(name="root", context=sc, parent=None)
span.start(); span.end()
pb = _encode_span(span)
assert (pb.flags & PB2SpanFlags.SPAN_FLAGS_TRACE_FLAGS_MASK) == 0x01
assert (pb.flags & PB2SpanFlags.SPAN_FLAGS_CONTEXT_HAS_IS_REMOTE_MASK) != 0
assert (pb.flags & PB2SpanFlags.SPAN_FLAGS_CONTEXT_IS_REMOTE_MASK) == 0
assert (pb.flags & ~0x3FF) == 0

def test_span_flags_remote_parent_sampled(self):
parent = SDKSpanContext(0x1, 0x9, is_remote=True)
sc = SDKSpanContext(0x1, 0x2, is_remote=False, trace_flags=0x01)
span = SDKSpan(name="child", context=sc, parent=parent)
span.start(); span.end()
pb = _encode_span(span)
assert (pb.flags & PB2SpanFlags.SPAN_FLAGS_TRACE_FLAGS_MASK) == 0x01
assert (pb.flags & PB2SpanFlags.SPAN_FLAGS_CONTEXT_HAS_IS_REMOTE_MASK) != 0
assert (pb.flags & PB2SpanFlags.SPAN_FLAGS_CONTEXT_IS_REMOTE_MASK) != 0
assert (pb.flags & ~0x3FF) == 0

def test_link_flags_local_and_remote(self):
# local sampled link
l1 = SDKLink(SDKSpanContext(0x1, 0x2, is_remote=False, trace_flags=0x01))
# remote sampled link
l2 = SDKLink(SDKSpanContext(0x1, 0x3, is_remote=True, trace_flags=0x01))
pb_links = _encode_links([l1, l2])
assert (pb_links[0].flags & PB2SpanFlags.SPAN_FLAGS_TRACE_FLAGS_MASK) == 0x01
assert (pb_links[0].flags & PB2SpanFlags.SPAN_FLAGS_CONTEXT_HAS_IS_REMOTE_MASK) != 0
assert (pb_links[0].flags & PB2SpanFlags.SPAN_FLAGS_CONTEXT_IS_REMOTE_MASK) == 0
assert (pb_links[0].flags & ~0x3FF) == 0
assert (pb_links[1].flags & PB2SpanFlags.SPAN_FLAGS_TRACE_FLAGS_MASK) == 0x01
assert (pb_links[1].flags & PB2SpanFlags.SPAN_FLAGS_CONTEXT_HAS_IS_REMOTE_MASK) != 0
assert (pb_links[1].flags & PB2SpanFlags.SPAN_FLAGS_CONTEXT_IS_REMOTE_MASK) != 0
assert (pb_links[1].flags & ~0x3FF) == 0
Original file line number Diff line number Diff line change
Expand Up @@ -466,7 +466,7 @@ def test_translate_spans(self):
),
),
],
flags=0x300,
flags=0x300, # updated below in more focused tests
)
],
flags=0x300,
Expand Down Expand Up @@ -570,10 +570,10 @@ def test_translate_spans_multi(self):
),
),
],
flags=0x300,
flags=0x301,
)
],
flags=0x300,
flags=0x301,
)
],
),
Expand Down Expand Up @@ -603,7 +603,7 @@ def test_translate_spans_multi(self):
OTLPSpan.SpanKind.SPAN_KIND_INTERNAL
),
status=Status(code=0, message=""),
flags=0x300,
flags=0x301,
)
],
),
Expand Down Expand Up @@ -645,7 +645,7 @@ def test_translate_spans_multi(self):
OTLPSpan.SpanKind.SPAN_KIND_INTERNAL
),
status=Status(code=0, message=""),
flags=0x300,
flags=0x301,
)
],
)
Expand Down