Skip to content

Add sentry_meta object to Span and pass it through to ReadableSpan #3676

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Oct 21, 2024
Merged
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
37 changes: 36 additions & 1 deletion sentry_sdk/integrations/opentelemetry/integration.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@
try:
from opentelemetry import trace
from opentelemetry.propagate import set_global_textmap
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.trace import Span as AbstractSpan
from opentelemetry.sdk.trace import TracerProvider, Span, ReadableSpan
except ImportError:
raise DidNotEnable("opentelemetry not installed")

Expand All @@ -27,6 +28,11 @@
except ImportError:
DjangoInstrumentor = None

from sentry_sdk._types import TYPE_CHECKING

if TYPE_CHECKING:
from typing import Union, Any


CONFIGURABLE_INSTRUMENTATIONS = {
DjangoInstrumentor: {"is_sql_commentor_enabled": True},
Expand All @@ -45,11 +51,40 @@ def setup_once():
)

_setup_sentry_tracing()
_patch_readable_span()
# _setup_instrumentors()

logger.debug("[OTel] Finished setting up OpenTelemetry integration")


def _patch_readable_span():
# type: () -> None
"""
We need to pass through sentry specific metadata/objects from Span to ReadableSpan
to work with them consistently in the SpanProcessor.
"""

@property
def sentry_meta(self):
# type: (Union[AbstractSpan, Span, ReadableSpan]) -> dict[str, Any]
if not getattr(self, "_sentry_meta", None):
self._sentry_meta = {}
return self._sentry_meta

AbstractSpan.sentry_meta = sentry_meta
ReadableSpan.sentry_meta = sentry_meta

old_readable_span = Span._readable_span

def sentry_patched_readable_span(self):
# type: (Span) -> ReadableSpan
readable_span = old_readable_span(self)
readable_span._sentry_meta = self._sentry_meta
return readable_span

Span._readable_span = sentry_patched_readable_span


def _setup_sentry_tracing():
# type: () -> None
import opentelemetry.context
Expand Down
10 changes: 5 additions & 5 deletions sentry_sdk/integrations/opentelemetry/potel_span_processor.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
format_span_id,
get_current_span,
INVALID_SPAN,
Span as TraceApiSpan,
Span as AbstractSpan,
)
from opentelemetry.context import Context
from opentelemetry.sdk.trace import Span, ReadableSpan, SpanProcessor
Expand Down Expand Up @@ -78,19 +78,19 @@ def force_flush(self, timeout_millis=30000):
return True

def _add_root_span(self, span, parent_span):
# type: (Span, TraceApiSpan) -> None
# type: (Span, AbstractSpan) -> None
"""
This is required to make POTelSpan.root_span work
since we can't traverse back to the root purely with otel efficiently.
"""
if parent_span != INVALID_SPAN and not parent_span.get_span_context().is_remote:
# child span points to parent's root or parent
span._sentry_root_otel_span = getattr(
parent_span, "_sentry_root_otel_span", parent_span
span.sentry_meta["root_span"] = parent_span.sentry_meta.get(
"root_span", parent_span
)
else:
# root span points to itself
span._sentry_root_otel_span = span
span.sentry_meta["root_span"] = span

def _flush_root_span(self, span):
# type: (ReadableSpan) -> None
Expand Down
3 changes: 1 addition & 2 deletions sentry_sdk/tracing.py
Original file line number Diff line number Diff line change
Expand Up @@ -1327,8 +1327,7 @@ def containing_transaction(self):
def root_span(self):
# type: () -> Optional[POTelSpan]
root_otel_span = cast(
"Optional[OtelSpan]",
getattr(self._otel_span, "_sentry_root_otel_span", None),
"Optional[OtelSpan]", self._otel_span.sentry_meta.get("root_span", None)
)
return POTelSpan(otel_span=root_otel_span) if root_otel_span else None

Expand Down
Loading