Skip to content

Commit 275c63e

Browse files
ref(sessions): Deprecate hub-based sessions.py logic (#3419)
Make several changes to prepare for fully removing Hubs in the next major: - Deprecate the Hub-based `auto_session_tracking` function, replacing it with a new Scope-based function called `track_session` - Deprecate the scope-based `auto_session_tracking_scope` in favor of the new `track_session` function - Change usages of `auto_session_tracking_scope` to `track_sessions`. There are no usages of `auto_session_tracking` outside of tests. - Run all tests that were previously run against `auto_session_tracking` also against the new `track_session`. Previously, `auto_session_tracking_scope` was completely untested. Fixes #3417
1 parent 6a4e729 commit 275c63e

File tree

5 files changed

+139
-15
lines changed

5 files changed

+139
-15
lines changed

sentry_sdk/integrations/aiohttp.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
from sentry_sdk.consts import OP, SPANSTATUS, SPANDATA
77
from sentry_sdk.integrations import Integration, DidNotEnable
88
from sentry_sdk.integrations.logging import ignore_logger
9-
from sentry_sdk.sessions import auto_session_tracking_scope
9+
from sentry_sdk.sessions import track_session
1010
from sentry_sdk.integrations._wsgi_common import (
1111
_filter_headers,
1212
request_body_within_bounds,
@@ -105,7 +105,7 @@ async def sentry_app_handle(self, request, *args, **kwargs):
105105
weak_request = weakref.ref(request)
106106

107107
with sentry_sdk.isolation_scope() as scope:
108-
with auto_session_tracking_scope(scope, session_mode="request"):
108+
with track_session(scope, session_mode="request"):
109109
# Scope data will not leak between requests because aiohttp
110110
# create a task to wrap each request.
111111
scope.generate_propagation_context()

sentry_sdk/integrations/asgi.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
_get_request_data,
2020
_get_url,
2121
)
22-
from sentry_sdk.sessions import auto_session_tracking_scope
22+
from sentry_sdk.sessions import track_session
2323
from sentry_sdk.tracing import (
2424
SOURCE_FOR_STYLE,
2525
TRANSACTION_SOURCE_ROUTE,
@@ -169,7 +169,7 @@ async def _run_app(self, scope, receive, send, asgi_version):
169169
_asgi_middleware_applied.set(True)
170170
try:
171171
with sentry_sdk.isolation_scope() as sentry_scope:
172-
with auto_session_tracking_scope(sentry_scope, session_mode="request"):
172+
with track_session(sentry_scope, session_mode="request"):
173173
sentry_scope.clear_breadcrumbs()
174174
sentry_scope._name = "asgi"
175175
processor = partial(self.event_processor, asgi_scope=scope)

sentry_sdk/integrations/wsgi.py

+2-4
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,7 @@
88
from sentry_sdk.consts import OP
99
from sentry_sdk.scope import should_send_default_pii
1010
from sentry_sdk.integrations._wsgi_common import _filter_headers
11-
from sentry_sdk.sessions import (
12-
auto_session_tracking_scope as auto_session_tracking,
13-
) # When the Hub is removed, this should be renamed (see comment in sentry_sdk/sessions.py)
11+
from sentry_sdk.sessions import track_session
1412
from sentry_sdk.scope import use_isolation_scope
1513
from sentry_sdk.tracing import Transaction, TRANSACTION_SOURCE_ROUTE
1614
from sentry_sdk.utils import (
@@ -83,7 +81,7 @@ def __call__(self, environ, start_response):
8381
_wsgi_middleware_applied.set(True)
8482
try:
8583
with sentry_sdk.isolation_scope() as scope:
86-
with auto_session_tracking(scope, session_mode="request"):
84+
with track_session(scope, session_mode="request"):
8785
with capture_internal_exceptions():
8886
scope.clear_breadcrumbs()
8987
scope._name = "wsgi"

sentry_sdk/sessions.py

+28-6
Original file line numberDiff line numberDiff line change
@@ -47,8 +47,15 @@ def is_auto_session_tracking_enabled(hub=None):
4747
@contextmanager
4848
def auto_session_tracking(hub=None, session_mode="application"):
4949
# type: (Optional[sentry_sdk.Hub], str) -> Generator[None, None, None]
50-
"""Starts and stops a session automatically around a block."""
51-
# TODO: add deprecation warning
50+
"""DEPRECATED: Use track_session instead
51+
Starts and stops a session automatically around a block.
52+
"""
53+
warnings.warn(
54+
"This function is deprecated and will be removed in the next major release. "
55+
"Use track_session instead.",
56+
DeprecationWarning,
57+
stacklevel=2,
58+
)
5259

5360
if hub is None:
5461
hub = sentry_sdk.Hub.current
@@ -98,13 +105,28 @@ def _is_auto_session_tracking_enabled(scope):
98105
@contextmanager
99106
def auto_session_tracking_scope(scope, session_mode="application"):
100107
# type: (sentry_sdk.Scope, str) -> Generator[None, None, None]
101-
"""
108+
"""DEPRECATED: This function is a deprecated alias for track_session.
102109
Starts and stops a session automatically around a block.
110+
"""
103111

104-
TODO: This uses the new scopes. When the Hub is removed, the function
105-
auto_session_tracking should be removed and this function
106-
should be renamed to auto_session_tracking.
112+
warnings.warn(
113+
"This function is a deprecated alias for track_session and will be removed in the next major release.",
114+
DeprecationWarning,
115+
stacklevel=2,
116+
)
117+
118+
with track_session(scope, session_mode=session_mode):
119+
yield
120+
121+
122+
@contextmanager
123+
def track_session(scope, session_mode="application"):
124+
# type: (sentry_sdk.Scope, str) -> Generator[None, None, None]
107125
"""
126+
Start a new session in the provided scope, assuming session tracking is enabled.
127+
This is a no-op context manager if session tracking is not enabled.
128+
"""
129+
108130
should_track = _is_auto_session_tracking_enabled(scope)
109131
if should_track:
110132
scope.start_session(session_mode=session_mode)

tests/test_sessions.py

+105-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
from unittest import mock
22

33
import sentry_sdk
4-
from sentry_sdk.sessions import auto_session_tracking
4+
from sentry_sdk.sessions import auto_session_tracking, track_session
55

66

77
def sorted_aggregates(item):
@@ -50,6 +50,48 @@ def test_aggregates(sentry_init, capture_envelopes):
5050
)
5151
envelopes = capture_envelopes()
5252

53+
with sentry_sdk.isolation_scope() as scope:
54+
with track_session(scope, session_mode="request"):
55+
try:
56+
scope.set_user({"id": "42"})
57+
raise Exception("all is wrong")
58+
except Exception:
59+
sentry_sdk.capture_exception()
60+
61+
with sentry_sdk.isolation_scope() as scope:
62+
with track_session(scope, session_mode="request"):
63+
pass
64+
65+
sentry_sdk.get_isolation_scope().start_session(session_mode="request")
66+
sentry_sdk.get_isolation_scope().end_session()
67+
sentry_sdk.flush()
68+
69+
assert len(envelopes) == 2
70+
assert envelopes[0].get_event() is not None
71+
72+
sess = envelopes[1]
73+
assert len(sess.items) == 1
74+
sess_event = sess.items[0].payload.json
75+
assert sess_event["attrs"] == {
76+
"release": "fun-release",
77+
"environment": "not-fun-env",
78+
}
79+
80+
aggregates = sorted_aggregates(sess_event)
81+
assert len(aggregates) == 1
82+
assert aggregates[0]["exited"] == 2
83+
assert aggregates[0]["errored"] == 1
84+
85+
86+
def test_aggregates_deprecated(
87+
sentry_init, capture_envelopes, suppress_deprecation_warnings
88+
):
89+
sentry_init(
90+
release="fun-release",
91+
environment="not-fun-env",
92+
)
93+
envelopes = capture_envelopes()
94+
5395
with auto_session_tracking(session_mode="request"):
5496
with sentry_sdk.new_scope() as scope:
5597
try:
@@ -90,6 +132,39 @@ def test_aggregates_explicitly_disabled_session_tracking_request_mode(
90132
)
91133
envelopes = capture_envelopes()
92134

135+
with sentry_sdk.isolation_scope() as scope:
136+
with track_session(scope, session_mode="request"):
137+
try:
138+
raise Exception("all is wrong")
139+
except Exception:
140+
sentry_sdk.capture_exception()
141+
142+
with sentry_sdk.isolation_scope() as scope:
143+
with track_session(scope, session_mode="request"):
144+
pass
145+
146+
sentry_sdk.get_isolation_scope().start_session(session_mode="request")
147+
sentry_sdk.get_isolation_scope().end_session()
148+
sentry_sdk.flush()
149+
150+
sess = envelopes[1]
151+
assert len(sess.items) == 1
152+
sess_event = sess.items[0].payload.json
153+
154+
aggregates = sorted_aggregates(sess_event)
155+
assert len(aggregates) == 1
156+
assert aggregates[0]["exited"] == 1
157+
assert "errored" not in aggregates[0]
158+
159+
160+
def test_aggregates_explicitly_disabled_session_tracking_request_mode_deprecated(
161+
sentry_init, capture_envelopes, suppress_deprecation_warnings
162+
):
163+
sentry_init(
164+
release="fun-release", environment="not-fun-env", auto_session_tracking=False
165+
)
166+
envelopes = capture_envelopes()
167+
93168
with auto_session_tracking(session_mode="request"):
94169
with sentry_sdk.new_scope():
95170
try:
@@ -120,6 +195,35 @@ def test_no_thread_on_shutdown_no_errors(sentry_init):
120195
environment="not-fun-env",
121196
)
122197

198+
# make it seem like the interpreter is shutting down
199+
with mock.patch(
200+
"threading.Thread.start",
201+
side_effect=RuntimeError("can't create new thread at interpreter shutdown"),
202+
):
203+
with sentry_sdk.isolation_scope() as scope:
204+
with track_session(scope, session_mode="request"):
205+
try:
206+
raise Exception("all is wrong")
207+
except Exception:
208+
sentry_sdk.capture_exception()
209+
210+
with sentry_sdk.isolation_scope() as scope:
211+
with track_session(scope, session_mode="request"):
212+
pass
213+
214+
sentry_sdk.get_isolation_scope().start_session(session_mode="request")
215+
sentry_sdk.get_isolation_scope().end_session()
216+
sentry_sdk.flush()
217+
218+
219+
def test_no_thread_on_shutdown_no_errors_deprecated(
220+
sentry_init, suppress_deprecation_warnings
221+
):
222+
sentry_init(
223+
release="fun-release",
224+
environment="not-fun-env",
225+
)
226+
123227
# make it seem like the interpreter is shutting down
124228
with mock.patch(
125229
"threading.Thread.start",

0 commit comments

Comments
 (0)