8000 Use root span transaction name in populated head DSC by sl0thentr0py · Pull Request #3677 · getsentry/sentry-python · GitHub
[go: up one dir, main page]

Skip to content

Use root span transaction name in populated head DSC #3677

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 22, 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
19 changes: 1 addition & 18 deletions sentry_sdk/integrations/opentelemetry/integration.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@
try:
from opentelemetry import trace
from opentelemetry.propagate import set_global_textmap
from opentelemetry.trace import Span as AbstractSpan
from opentelemetry.sdk.trace import TracerProvider, Span, ReadableSpan
except ImportError:
raise DidNotEnable("opentelemetry not installed")
Expand All @@ -28,11 +27,6 @@
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 Down Expand Up @@ -63,23 +57,12 @@ def _patch_readable_span():
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
readable_span._sentry_meta = getattr(self, "_sentry_meta", {})
return readable_span

Span._readable_span = sentry_patched_readable_span
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@
extract_span_data,
extract_transaction_name_source,
get_trace_context,
get_sentry_meta,
set_sentry_meta,
)
from sentry_sdk.integrations.opentelemetry.consts import (
OTEL_SENTRY_CONTEXT,
Expand Down Expand Up @@ -85,12 +87,11 @@ def _add_root_span(self, span, parent_span):
"""
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_meta["root_span"] = parent_span.sentry_meta.get(
"root_span", parent_span
)
parent_root_span = get_sentry_meta(parent_span, "root_span")
set_sentry_meta(span, "root_span", parent_root_span or parent_span)
else:
# root span points to itself
span.sentry_meta["root_span"] = span
set_sentry_meta(span, "root_span", span)

def _flush_root_span(self, span):
# type: (ReadableSpan) -> None
Expand Down
50 changes: 27 additions & 23 deletions sentry_sdk/integrations/opentelemetry/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
from urllib3.util import parse_url as urlparse
from urllib.parse import quote
from opentelemetry.trace import (
Span,
Span as AbstractSpan,
SpanKind,
StatusCode,
format_trace_id,
Expand Down Expand Up @@ -365,7 +365,7 @@ def has_incoming_trace(trace_state):


def get_trace_state(span):
# type: (Union[Span, ReadableSpan]) -> TraceState
# type: (Union[AbstractSpan, ReadableSpan]) -> TraceState
"""
Get the existing trace_state with sentry items
or populate it if we are the head SDK.
Expand Down Expand Up @@ -404,27 +404,31 @@ def get_trace_state(span):
Baggage.SENTRY_PREFIX + "public_key", Dsn(options["dsn"]).public_key
)

# we cannot access the root span in most cases here, so we HAVE to rely on the
# scopes to carry the correct transaction name/source.
# IDEALLY we will always move to using the isolation scope here
# but our integrations do all kinds of stuff with both isolation and current
# so I am keeping both for now as a best attempt solution till we get to a better state.
isolation_scope = sentry_sdk.get_isolation_scope()
current_scope = sentry_sdk.get_current_scope()
if (
current_scope.transaction_name
and current_scope.transaction_source not in LOW_QUALITY_TRANSACTION_SOURCES
):
trace_state = trace_state.update(
Baggage.SENTRY_PREFIX + "transaction", current_scope.transaction_name
)
elif (
isolation_scope.transaction_name
and isolation_scope.transaction_source
not in LOW_QUALITY_TRANSACTION_SOURCES
):
trace_state = trace_state.update(
Baggage.SENTRY_PREFIX + "transaction", isolation_scope.transaction_name
root_span = get_sentry_meta(span, "root_span")
if root_span and isinstance(root_span, ReadableSpan):
transaction_name, transaction_source = extract_transaction_name_source(
root_span
)

if (
transaction_name
and transaction_source not in LOW_QUALITY_TRANSACTION_SOURCES
):
trace_state = trace_state.update(
Baggage.SENTRY_PREFIX + "transaction", transaction_name
)

return trace_state


def get_sentry_meta(span, key):
# type: (Union[AbstractSpan, ReadableSpan], str) -> Any
sentry_meta = getattr(span, "_sentry_meta", None)
return sentry_meta.get(key) if sentry_meta else None


def set_sentry_meta(span, key, value):
# type: (Union[AbstractSpan, ReadableSpan], str, Any) -> None
sentry_meta = getattr(span, "_sentry_meta", {})
sentry_meta[key] = value
span._sentry_meta = sentry_meta
6 changes: 5 additions & 1 deletion sentry_sdk/tracing.py
Original file line number Diff line number Diff line change
Expand Up @@ -1326,8 +1326,12 @@ def containing_transaction(self):
@property
def root_span(self):
# type: () -> Optional[POTelSpan]
from sentry_sdk.integrations.opentelemetry.utils import (
get_sentry_meta,
)

root_otel_span = cast(
"Optional[OtelSpan]", self._otel_span.sentry_meta.get("root_span", None)
"Optional[OtelSpan]", get_sentry_meta(self._otel_span, "root_span")
)
return POTelSpan(otel_span=root_otel_span) if root_otel_span else None

Expand Down
Loading
0