diff --git a/sentry_sdk/scope.py b/sentry_sdk/scope.py index c721b56505..e5478cebc9 100644 --- a/sentry_sdk/scope.py +++ b/sentry_sdk/scope.py @@ -134,10 +134,33 @@ def fingerprint(self, value): """When set this overrides the default fingerprint.""" self._fingerprint = value - @_attr_setter + @property + def transaction(self): + # type: () -> Any + # would be type: () -> Optional[Span], see https://github.com/python/mypy/issues/3004 + # XXX: update return type to Optional[Transaction] + """Return the transaction (root span) in the scope.""" + if self._span is None or self._span._span_recorder is None: + return None + try: + return self._span._span_recorder.spans[0] + except (AttributeError, IndexError): + return None + + @transaction.setter def transaction(self, value): - # type: (Optional[str]) -> None + # type: (Any) -> None + # would be type: (Optional[str]) -> None, see https://github.com/python/mypy/issues/3004 """When set this forces a specific transaction name to be set.""" + # XXX: the docstring above is misleading. The implementation of + # apply_to_event prefers an existing value of event.transaction over + # anything set in the scope. + # XXX: note that with the introduction of the Scope.transaction getter, + # there is a semantic and type mismatch between getter and setter. The + # getter returns a transaction, the setter sets a transaction name. + # Without breaking version compatibility, we could make the setter set a + # transaction name or transaction (self._span) depending on the type of + # the value argument. self._transaction = value span = self._span if span: diff --git a/tests/test_tracing.py b/tests/test_tracing.py index af479ee90d..d49eeaf826 100644 --- a/tests/test_tracing.py +++ b/tests/test_tracing.py @@ -3,7 +3,7 @@ import pytest -from sentry_sdk import Hub, capture_message +from sentry_sdk import Hub, capture_message, start_span from sentry_sdk.tracing import Span @@ -181,3 +181,17 @@ def before_send(event, hint): pass assert len(events) == 1 + + +def test_get_transaction_from_scope(sentry_init, capture_events): + sentry_init(traces_sample_rate=1.0) + events = capture_events() + + with start_span(transaction="/"): + with start_span(op="child-span"): + with start_span(op="child-child-span"): + scope = Hub.current.scope + assert scope.span.op == "child-child-span" + assert scope.transaction.transaction == "/" + + assert len(events) == 1