Skip to content

Commit 0c37864

Browse files
feat(scope): Replace transaction with root_span
Closes #4235
1 parent 6584ce0 commit 0c37864

File tree

12 files changed

+48
-34
lines changed

12 files changed

+48
-34
lines changed

MIGRATION_GUIDE.md

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ Looking to upgrade from Sentry SDK 2.x to 3.x? Here's a comprehensive list of wh
2727
- The `sampling_context` argument of `traces_sampler` and `profiles_sampler` now additionally contains all span attributes known at span start.
2828
- We updated how we handle `ExceptionGroup`s. You will now get more data if ExceptionGroups are appearing in chained exceptions. It could happen that after updating the SDK the grouping of issues change because of this. So eventually you will see the same exception in two Sentry issues (one from before the update, one from after the update)
2929
- The integration-specific content of the `sampling_context` argument of `traces_sampler` and `profiles_sampler` now looks different.
30+
3031
- The Celery integration doesn't add the `celery_job` dictionary anymore. Instead, the individual keys are now available as:
3132

3233
| Dictionary keys | Sampling context key | Example |
@@ -93,15 +94,15 @@ Looking to upgrade from Sentry SDK 2.x to 3.x? Here's a comprehensive list of wh
9394

9495
-The RQ integration doesn't add the `rq_job` object anymore. Instead, the individual properties of the job and the queue, if available, are accessible as follows:
9596

96-
| RQ property | Sampling context key | Example |
97-
| --------------- | ---------------------------- | ---------------------- |
98-
| `rq_job.args` | `rq.job.args.{index}` | `rq.job.args.0` |
99-
| `rq_job.kwargs` | `rq.job.kwargs.{kwarg}` | `rq.job.args.my_kwarg` |
100-
| `rq_job.func` | `rq.job.func` | |
101-
| `queue.name` | `messaging.destination.name` | |
102-
| `rq_job.id` | `messaging.message.id` | |
97+
| RQ property | Sampling context key | Example |
98+
| --------------- | ---------------------------- | ---------------------- |
99+
| `rq_job.args` | `rq.job.args.{index}` | `rq.job.args.0` |
100+
| `rq_job.kwargs` | `rq.job.kwargs.{kwarg}` | `rq.job.args.my_kwarg` |
101+
| `rq_job.func` | `rq.job.func` | |
102+
| `queue.name` | `messaging.destination.name` | |
103+
| `rq_job.id` | `messaging.message.id` | |
103104

104-
Note that `rq.job.args`, `rq.job.kwargs`, and `rq.job.func` are serialized and not the actual objects on the job.
105+
Note that `rq.job.args`, `rq.job.kwargs`, and `rq.job.func` are serialized and not the actual objects on the job.
105106

106107
- The AWS Lambda integration doesn't add the `aws_event` and `aws_context` objects anymore. Instead, the following, if available, is accessible:
107108

@@ -129,7 +130,6 @@ Looking to upgrade from Sentry SDK 2.x to 3.x? Here's a comprehensive list of wh
129130
| `gcp_event.query_string` | `url.query` |
130131
| `gcp_event.headers` | `http.request.header.{header}` |
131132

132-
133133
### Removed
134134

135135
- Dropped support for Python 3.6.
@@ -162,7 +162,7 @@ Looking to upgrade from Sentry SDK 2.x to 3.x? Here's a comprehensive list of wh
162162
- `same_process_as_parent`
163163
- `span_id`
164164
- `parent_span_id`: you can supply a `parent_span` instead
165-
- Setting `Scope.transaction` directly is no longer supported. Use `Scope.set_transaction_name()` instead.
165+
- The `Scope.transaction` property has been removed. To obtain the root span, use `Scope.root_span`. To set the root span's name, use `Scope.set_transaction_name()`.
166166
- Passing a list or `None` for `failed_request_status_codes` in the Starlette integration is no longer supported. Pass a set of integers instead.
167167
- The `span` argument of `Scope.trace_propagation_meta` is no longer supported.
168168
- Setting `Scope.user` directly is no longer supported. Use `Scope.set_user()` instead.

sentry_sdk/api.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -299,7 +299,7 @@ def start_transaction(
299299

300300
def set_measurement(name, value, unit=""):
301301
# type: (str, float, MeasurementUnit) -> None
302-
transaction = get_current_scope().transaction
302+
transaction = get_current_scope().root_span
303303
if transaction is not None:
304304
transaction.set_measurement(name, value, unit)
305305

sentry_sdk/client.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -850,7 +850,7 @@ def _capture_experimental_log(self, current_scope, log):
850850
log["attributes"]["sentry.trace.parent_span_id"] = span.span_id
851851

852852
if log.get("trace_id") is None:
853-
transaction = current_scope.transaction
853+
transaction = current_scope.root_span
854854
propagation_context = isolation_scope.get_active_propagation_context()
855855
if transaction is not None:
856856
log["trace_id"] = transaction.trace_id

sentry_sdk/integrations/arq.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -127,12 +127,12 @@ def _capture_exception(exc_info):
127127
# type: (ExcInfo) -> None
128128
scope = sentry_sdk.get_current_scope()
129129

130-
if scope.transaction is not None:
130+
if scope.root_span is not None:
131131
if exc_info[0] in ARQ_CONTROL_FLOW_EXCEPTIONS:
132-
scope.transaction.set_status(SPANSTATUS.ABORTED)
132+
scope.root_span.set_status(SPANSTATUS.ABORTED)
133133
return
134134

135-
scope.transaction.set_status(SPANSTATUS.INTERNAL_ERROR)
135+
scope.root_span.set_status(SPANSTATUS.INTERNAL_ERROR)
136136

137137
event, hint = event_from_exception(
138138
exc_info,
@@ -149,8 +149,8 @@ def event_processor(event, hint):
149149

150150
with capture_internal_exceptions():
151151
scope = sentry_sdk.get_current_scope()
152-
if scope.transaction is not None:
153-
scope.transaction.name = ctx["job_name"]
152+
if scope.root_span is not None:
153+
scope.root_span.name = ctx["job_name"]
154154
event["transaction"] = ctx["job_name"]
155155

156156
tags = event.setdefault("tags", {})

sentry_sdk/integrations/django/asgi.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -176,8 +176,8 @@ def wrap_async_view(callback):
176176
async def sentry_wrapped_callback(request, *args, **kwargs):
177177
# type: (Any, *Any, **Any) -> Any
178178
current_scope = sentry_sdk.get_current_scope()
179-
if current_scope.transaction is not None:
180-
current_scope.transaction.update_active_thread()
179+
if current_scope.root_span is not None:
180+
current_scope.root_span.update_active_thread()
181181

182182
sentry_scope = sentry_sdk.get_isolation_scope()
183183
if sentry_scope.profile is not None:

sentry_sdk/integrations/django/views.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -79,8 +79,8 @@ def _wrap_sync_view(callback):
7979
def sentry_wrapped_callback(request, *args, **kwargs):
8080
# type: (Any, *Any, **Any) -> Any
8181
current_scope = sentry_sdk.get_current_scope()
82-
if current_scope.transaction is not None:
83-
current_scope.transaction.update_active_thread()
82+
if current_scope.root_span is not None:
83+
current_scope.root_span.update_active_thread()
8484

8585
sentry_scope = sentry_sdk.get_isolation_scope()
8686
# set the active thread id to the handler thread for sync views

sentry_sdk/integrations/fastapi.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -89,8 +89,8 @@ def _sentry_get_request_handler(*args, **kwargs):
8989
def _sentry_call(*args, **kwargs):
9090
# type: (*Any, **Any) -> Any
9191
current_scope = sentry_sdk.get_current_scope()
92-
if current_scope.transaction is not None:
93-
current_scope.transaction.update_active_thread()
92+
if current_scope.root_span is not None:
93+
current_scope.root_span.update_active_thread()
9494

9595
sentry_scope = sentry_sdk.get_isolation_scope()
9696
if sentry_scope.profile is not None:

sentry_sdk/integrations/huey.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -111,10 +111,10 @@ def _capture_exception(exc_info):
111111
scope = sentry_sdk.get_current_scope()
112112

113113
if exc_info[0] in HUEY_CONTROL_FLOW_EXCEPTIONS:
114-
scope.transaction.set_status(SPANSTATUS.ABORTED)
114+
scope.root_span.set_status(SPANSTATUS.ABORTED)
115115
return
116116

117-
scope.transaction.set_status(SPANSTATUS.INTERNAL_ERROR)
117+
scope.root_span.set_status(SPANSTATUS.INTERNAL_ERROR)
118118
event, hint = event_from_exception(
119119
exc_info,
120120
client_options=sentry_sdk.get_client().options,
@@ -136,7 +136,7 @@ def _sentry_execute(*args, **kwargs):
136136
_capture_exception(exc_info)
137137
reraise(*exc_info)
138138
else:
139-
sentry_sdk.get_current_scope().transaction.set_status(SPANSTATUS.OK)
139+
sentry_sdk.get_current_scope().root_span.set_status(SPANSTATUS.OK)
140140

141141
return result
142142

sentry_sdk/integrations/quart.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -122,8 +122,8 @@ def decorator(old_func):
122122
def _sentry_func(*args, **kwargs):
123123
# type: (*Any, **Any) -> Any
124124
current_scope = sentry_sdk.get_current_scope()
125-
if current_scope.transaction is not None:
126-
current_scope.transaction.update_active_thread()
125+
if current_scope.root_span is not None:
126+
current_scope.root_span.update_active_thread()
127127

128128
sentry_scope = sentry_sdk.get_isolation_scope()
129129
if sentry_scope.profile is not None:

sentry_sdk/integrations/starlette.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -477,8 +477,8 @@ def _sentry_sync_func(*args, **kwargs):
477477
return old_func(*args, **kwargs)
478478

479479
current_scope = sentry_sdk.get_current_scope()
480-
if current_scope.transaction is not None:
481-
current_scope.transaction.update_active_thread()
480+
if current_scope.root_span is not None:
481+
current_scope.root_span.update_active_thread()
482482

483483
sentry_scope = sentry_sdk.get_isolation_scope()
484484
if sentry_scope.profile is not None:

sentry_sdk/scope.py

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -688,10 +688,9 @@ def fingerprint(self, value):
688688
self._fingerprint = value
689689

690690
@property
691-
def transaction(self):
692-
# type: () -> Any
693-
# would be type: () -> Optional[Span], see https://github.com/python/mypy/issues/3004
694-
"""Return the transaction (root span) in the scope, if any."""
691+
def root_span(self):
692+
# type: () -> Optional[Span]
693+
"""Return the root span in the scope, if any."""
695694

696695
# there is no span/transaction on the scope
697696
if self._span is None:

tests/test_scope.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -915,3 +915,18 @@ def test_last_event_id_cleared(sentry_init):
915915
Scope.get_isolation_scope().clear()
916916

917917
assert Scope.last_event_id() is None, "last_event_id should be cleared"
918+
919+
920+
def test_root_span(sentry_init):
921+
sentry_init(traces_sample_rate=1.0)
922+
923+
assert sentry_sdk.get_current_scope().root_span is None
924+
925+
with sentry_sdk.start_span(name="test") as root_span:
926+
assert sentry_sdk.get_current_scope().root_span == root_span
927+
with sentry_sdk.start_span(name="child"):
928+
assert sentry_sdk.get_current_scope().root_span == root_span
929+
with sentry_sdk.start_span(name="grandchild"):
930+
assert sentry_sdk.get_current_scope().root_span == root_span
931+
932+
assert sentry_sdk.get_current_scope().root_span is None

0 commit comments

Comments
 (0)