Repository: open-telemetry/opentelemetry-python

Issue:
Add is_remote_parent span flags to OTLP exported Spans and SpanLinks
**Is your feature request related to a problem?**

After updating protobuf schema to 1.2.0 in 1164ab6c0193f658712b55469ecafbf031badc3b we can set the is_remote_parent flag when exporting spans and span links with OTLP. 

**Describe the solution you'd like**

Update OTLP exporter to fill the relevant bits in SpanFlags.

**Describe alternatives you've considered**

none

**Additional context**

Proto schema PR: https://github.com/open-telemetry/opentelemetry-proto/pull/484
Go implementation: https://github.com/open-telemetry/opentelemetry-go/pull/5194/files


Discussion:

Resolving patch:
diff --git a/exporter/opentelemetry-exporter-otlp-proto-common/src/opentelemetry/exporter/otlp/proto/common/_internal/trace_encoder/__init__.py b/exporter/opentelemetry-exporter-otlp-proto-common/src/opentelemetry/exporter/otlp/proto/common/_internal/trace_encoder/__init__.py
--- a/exporter/opentelemetry-exporter-otlp-proto-common/src/opentelemetry/exporter/otlp/proto/common/_internal/trace_encoder/__init__.py
+++ b/exporter/opentelemetry-exporter-otlp-proto-common/src/opentelemetry/exporter/otlp/proto/common/_internal/trace_encoder/__init__.py
@@ -17,27 +17,25 @@
 from typing import List, Optional, Sequence
 
 from opentelemetry.exporter.otlp.proto.common._internal import (
-    _encode_trace_id,
-    _encode_span_id,
-    _encode_instrumentation_scope,
     _encode_attributes,
+    _encode_instrumentation_scope,
     _encode_resource,
+    _encode_span_id,
+    _encode_trace_id,
 )
 from opentelemetry.proto.collector.trace.v1.trace_service_pb2 import (
     ExportTraceServiceRequest as PB2ExportTraceServiceRequest,
 )
-from opentelemetry.proto.trace.v1.trace_pb2 import (
-    ScopeSpans as PB2ScopeSpans,
-)
 from opentelemetry.proto.trace.v1.trace_pb2 import (
     ResourceSpans as PB2ResourceSpans,
 )
+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 SpanFlags as PB2SpanFlags
 from opentelemetry.proto.trace.v1.trace_pb2 import Status as PB2Status
 from opentelemetry.sdk.trace import Event, ReadableSpan
-from opentelemetry.trace import Link
-from opentelemetry.trace import SpanKind
-from opentelemetry.trace.span import SpanContext, TraceState, Status
+from opentelemetry.trace import Link, SpanKind
+from opentelemetry.trace.span import SpanContext, Status, TraceState
 
 # pylint: disable=E1101
 _SPAN_KIND_MAP = {
@@ -104,6 +102,13 @@ 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
+    return flags
+
+
 def _encode_span(sdk_span: ReadableSpan) -> PB2SPan:
     span_context = sdk_span.get_span_context()
     return PB2SPan(
@@ -122,6 +127,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),
     )
 
 
@@ -152,6 +158,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.attributes.dropped,
+                flags=_span_flags(link.context),
             )
             pb2_links.append(encoded_link)
     return pb2_links


Test patch:
diff --git a/exporter/opentelemetry-exporter-otlp-proto-common/tests/test_trace_encoder.py b/exporter/opentelemetry-exporter-otlp-proto-common/tests/test_trace_encoder.py
--- a/exporter/opentelemetry-exporter-otlp-proto-common/tests/test_trace_encoder.py
+++ b/exporter/opentelemetry-exporter-otlp-proto-common/tests/test_trace_encoder.py
@@ -81,7 +81,7 @@ def get_exhaustive_otel_span_list() -> List[SDKSpan]:
         )
 
         parent_span_context = SDKSpanContext(
-            trace_id, 0x1111111111111111, is_remote=False
+            trace_id, 0x1111111111111111, is_remote=True
         )
 
         other_context = SDKSpanContext(
@@ -252,12 +252,14 @@ def get_exhaustive_test_spans(
                                                     ),
                                                 ),
                                             ],
+                                            flags=0x100,
                                         )
                                     ],
                                     status=PB2Status(
                                         code=SDKStatusCode.ERROR.value,
                                         message="Example description",
                                     ),
+                                    flags=0x300,
                                 )
                             ],
                         ),
@@ -284,6 +286,7 @@ def get_exhaustive_test_spans(
                                     events=None,
                                     links=None,
                                     status={},
+                                    flags=0x100,
                                 )
                             ],
                         ),
@@ -321,6 +324,7 @@ def get_exhaustive_test_spans(
                                     events=None,
                                     links=None,
                                     status={},
+                                    flags=0x100,
                                 ),
                                 PB2SPan(
                                     trace_id=trace_id,
@@ -346,6 +350,7 @@ def get_exhaustive_test_spans(
                                     events=None,
                                     links=None,
                                     status={},
+                                    flags=0x100,
                                 ),
                             ],
                         )
diff --git a/exporter/opentelemetry-exporter-otlp-proto-grpc/tests/test_otlp_trace_exporter.py b/exporter/opentelemetry-exporter-otlp-proto-grpc/tests/test_otlp_trace_exporter.py
--- a/exporter/opentelemetry-exporter-otlp-proto-grpc/tests/test_otlp_trace_exporter.py
+++ b/exporter/opentelemetry-exporter-otlp-proto-grpc/tests/test_otlp_trace_exporter.py
@@ -597,8 +597,10 @@ def test_translate_spans(self):
                                                     ),
                                                 ),
                                             ],
+                                            flags=0x300,
                                         )
                                     ],
+                                    flags=0x300,
                                 )
                             ],
                         )
@@ -699,8 +701,10 @@ def test_translate_spans_multi(self):
                                                     ),
                                                 ),
                                             ],
+                                            flags=0x300,
                                         )
                                     ],
+                                    flags=0x300,
                                 )
                             ],
                         ),
@@ -730,6 +734,7 @@ def test_translate_spans_multi(self):
                                         OTLPSpan.SpanKind.SPAN_KIND_INTERNAL
                                     ),
                                     status=Status(code=0, message=""),
+                                    flags=0x300,
                                 )
                             ],
                         ),
@@ -771,6 +776,7 @@ def test_translate_spans_multi(self):
                                         OTLPSpan.SpanKind.SPAN_KIND_INTERNAL
                                     ),
                                     status=Status(code=0, message=""),
+                                    flags=0x300,
                                 )
                             ],
                         )