Skip to content
Open
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
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,8 +105,12 @@ 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
def _span_flags(child_trace_flags: int, parent_span_context: Optional[SpanContext]) -> int:
# Lower 8 bits: W3C TraceFlags
flags = child_trace_flags & PB2SpanFlags.SPAN_FLAGS_TRACE_FLAGS_MASK
# Always indicate whether parent remote information is known
flags |= PB2SpanFlags.SPAN_FLAGS_CONTEXT_HAS_IS_REMOTE_MASK
# Set remote bit when applicable
if parent_span_context and parent_span_context.is_remote:
flags |= 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(span_context.trace_flags, 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(link.context.trace_flags, 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