diff --git a/sentry_sdk/api.py b/sentry_sdk/api.py index e724a3b317..db0ce275fd 100644 --- a/sentry_sdk/api.py +++ b/sentry_sdk/api.py @@ -237,7 +237,6 @@ def flush( def start_span( *, - span=None, custom_sampling_context=None, **kwargs, # type: Any ): @@ -255,7 +254,7 @@ def start_span( method. """ # TODO: Consider adding type hints to the method signature. - return get_current_scope().start_span(span, custom_sampling_context, **kwargs) + return get_current_scope().start_span(custom_sampling_context, **kwargs) def start_transaction( diff --git a/sentry_sdk/integrations/opentelemetry/potel_span_processor.py b/sentry_sdk/integrations/opentelemetry/potel_span_processor.py index db4c1f58d6..06376ec3e6 100644 --- a/sentry_sdk/integrations/opentelemetry/potel_span_processor.py +++ b/sentry_sdk/integrations/opentelemetry/potel_span_processor.py @@ -51,8 +51,7 @@ def on_end(self, span): if is_sentry_span(span): return - # TODO-neel-potel-remote only take parent if not remote - if span.parent: + if span.parent and not span.parent.is_remote: self._children_spans[span.parent.span_id].append(span) else: # if have a root span ending, we build a transaction and send it diff --git a/sentry_sdk/integrations/opentelemetry/scope.py b/sentry_sdk/integrations/opentelemetry/scope.py index 50a7e45b01..01bf693611 100644 --- a/sentry_sdk/integrations/opentelemetry/scope.py +++ b/sentry_sdk/integrations/opentelemetry/scope.py @@ -2,8 +2,10 @@ from contextlib import contextmanager from opentelemetry.context import get_value, set_value, attach, detach, get_current +from opentelemetry.trace import SpanContext, NonRecordingSpan, TraceFlags, use_span from sentry_sdk.scope import Scope, ScopeType +from sentry_sdk.tracing import POTelSpan from sentry_sdk.integrations.opentelemetry.consts import ( SENTRY_SCOPES_KEY, SENTRY_FORK_ISOLATION_SCOPE_KEY, @@ -14,6 +16,8 @@ if TYPE_CHECKING: from typing import Tuple, Optional, Generator, Dict, Any + from sentry_sdk._types import SamplingContext + class PotelScope(Scope): @classmethod @@ -61,10 +65,43 @@ def _get_isolation_scope(cls): @contextmanager def continue_trace(self, environ_or_headers): # type: (Dict[str, Any]) -> Generator[None, None, None] - with new_scope() as scope: - scope.generate_propagation_context(environ_or_headers) - # TODO-neel-potel add remote span on context + self.generate_propagation_context(environ_or_headers) + + span_context = self._incoming_otel_span_context() + if span_context is None: yield + else: + with use_span(NonRecordingSpan(span_context)): + yield + + def _incoming_otel_span_context(self): + # type: () -> Optional[SpanContext] + if self._propagation_context is None: + return None + # If sentry-trace extraction didn't have a parent_span_id, we don't have an upstream header + if self._propagation_context.parent_span_id is None: + return None + + trace_flags = TraceFlags( + TraceFlags.SAMPLED + if self._propagation_context.parent_sampled + else TraceFlags.DEFAULT + ) + + # TODO-neel-potel tracestate + span_context = SpanContext( + trace_id=int(self._propagation_context.trace_id, 16), # type: ignore + span_id=int(self._propagation_context.parent_span_id, 16), # type: ignore + is_remote=True, + trace_flags=trace_flags, + ) + + return span_context + + def start_span(self, custom_sampling_context=None, **kwargs): + # type: (Optional[SamplingContext], Any) -> POTelSpan + # TODO-neel-potel ideally want to remove the span argument, discuss with ivana + return POTelSpan(**kwargs, scope=self) _INITIAL_CURRENT_SCOPE = PotelScope(ty=ScopeType.CURRENT) diff --git a/sentry_sdk/tracing.py b/sentry_sdk/tracing.py index 43a17e44ff..66a3a7b7c7 100644 --- a/sentry_sdk/tracing.py +++ b/sentry_sdk/tracing.py @@ -3,6 +3,7 @@ from datetime import datetime, timedelta, timezone from opentelemetry import trace as otel_trace, context +from opentelemetry.trace import format_trace_id, format_span_id from opentelemetry.trace.status import StatusCode import sentry_sdk @@ -1346,13 +1347,13 @@ def parent_span_id(self): @property def trace_id(self): - # type: () -> Optional[str] - return self._otel_span.get_span_context().trace_id + # type: () -> str + return format_trace_id(self._otel_span.get_span_context().trace_id) @property def span_id(self): - # type: () -> Optional[str] - return self._otel_span.get_span_context().span_id + # type: () -> str + return format_span_id(self._otel_span.get_span_context().span_id) @property def sampled(self):