sentry-sdk 3.0.0a1__py2.py3-none-any.whl → 3.0.0a3__py2.py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of sentry-sdk might be problematic. Click here for more details.
- sentry_sdk/__init__.py +2 -0
- sentry_sdk/_compat.py +5 -12
- sentry_sdk/_init_implementation.py +7 -7
- sentry_sdk/_log_batcher.py +17 -29
- sentry_sdk/_lru_cache.py +7 -9
- sentry_sdk/_queue.py +2 -4
- sentry_sdk/_types.py +11 -18
- sentry_sdk/_werkzeug.py +5 -7
- sentry_sdk/ai/monitoring.py +44 -31
- sentry_sdk/ai/utils.py +3 -4
- sentry_sdk/api.py +75 -87
- sentry_sdk/attachments.py +10 -12
- sentry_sdk/client.py +137 -155
- sentry_sdk/consts.py +430 -174
- sentry_sdk/crons/api.py +16 -17
- sentry_sdk/crons/decorator.py +25 -27
- sentry_sdk/debug.py +4 -6
- sentry_sdk/envelope.py +46 -112
- sentry_sdk/feature_flags.py +9 -15
- sentry_sdk/integrations/__init__.py +24 -19
- sentry_sdk/integrations/_asgi_common.py +15 -18
- sentry_sdk/integrations/_wsgi_common.py +22 -33
- sentry_sdk/integrations/aiohttp.py +32 -30
- sentry_sdk/integrations/anthropic.py +42 -37
- sentry_sdk/integrations/argv.py +3 -4
- sentry_sdk/integrations/ariadne.py +16 -18
- sentry_sdk/integrations/arq.py +21 -29
- sentry_sdk/integrations/asgi.py +63 -37
- sentry_sdk/integrations/asyncio.py +14 -16
- sentry_sdk/integrations/atexit.py +6 -10
- sentry_sdk/integrations/aws_lambda.py +26 -36
- sentry_sdk/integrations/beam.py +10 -18
- sentry_sdk/integrations/boto3.py +18 -16
- sentry_sdk/integrations/bottle.py +25 -34
- sentry_sdk/integrations/celery/__init__.py +41 -61
- sentry_sdk/integrations/celery/beat.py +23 -27
- sentry_sdk/integrations/celery/utils.py +15 -17
- sentry_sdk/integrations/chalice.py +8 -10
- sentry_sdk/integrations/clickhouse_driver.py +21 -31
- sentry_sdk/integrations/cloud_resource_context.py +9 -16
- sentry_sdk/integrations/cohere.py +27 -33
- sentry_sdk/integrations/dedupe.py +5 -8
- sentry_sdk/integrations/django/__init__.py +57 -72
- sentry_sdk/integrations/django/asgi.py +26 -34
- sentry_sdk/integrations/django/caching.py +23 -19
- sentry_sdk/integrations/django/middleware.py +17 -20
- sentry_sdk/integrations/django/signals_handlers.py +11 -10
- sentry_sdk/integrations/django/templates.py +19 -16
- sentry_sdk/integrations/django/transactions.py +16 -11
- sentry_sdk/integrations/django/views.py +6 -10
- sentry_sdk/integrations/dramatiq.py +21 -21
- sentry_sdk/integrations/excepthook.py +10 -10
- sentry_sdk/integrations/executing.py +3 -4
- sentry_sdk/integrations/falcon.py +27 -42
- sentry_sdk/integrations/fastapi.py +13 -16
- sentry_sdk/integrations/flask.py +31 -38
- sentry_sdk/integrations/gcp.py +13 -16
- sentry_sdk/integrations/gnu_backtrace.py +4 -6
- sentry_sdk/integrations/gql.py +16 -17
- sentry_sdk/integrations/graphene.py +13 -12
- sentry_sdk/integrations/grpc/__init__.py +19 -1
- sentry_sdk/integrations/grpc/aio/server.py +15 -14
- sentry_sdk/integrations/grpc/client.py +19 -9
- sentry_sdk/integrations/grpc/consts.py +2 -0
- sentry_sdk/integrations/grpc/server.py +12 -8
- sentry_sdk/integrations/httpx.py +9 -12
- sentry_sdk/integrations/huey.py +13 -20
- sentry_sdk/integrations/huggingface_hub.py +18 -18
- sentry_sdk/integrations/langchain.py +203 -113
- sentry_sdk/integrations/launchdarkly.py +13 -10
- sentry_sdk/integrations/litestar.py +37 -35
- sentry_sdk/integrations/logging.py +52 -65
- sentry_sdk/integrations/loguru.py +127 -57
- sentry_sdk/integrations/modules.py +3 -4
- sentry_sdk/integrations/openai.py +100 -88
- sentry_sdk/integrations/openai_agents/__init__.py +49 -0
- sentry_sdk/integrations/openai_agents/consts.py +1 -0
- sentry_sdk/integrations/openai_agents/patches/__init__.py +4 -0
- sentry_sdk/integrations/openai_agents/patches/agent_run.py +152 -0
- sentry_sdk/integrations/openai_agents/patches/models.py +52 -0
- sentry_sdk/integrations/openai_agents/patches/runner.py +42 -0
- sentry_sdk/integrations/openai_agents/patches/tools.py +84 -0
- sentry_sdk/integrations/openai_agents/spans/__init__.py +5 -0
- sentry_sdk/integrations/openai_agents/spans/agent_workflow.py +20 -0
- sentry_sdk/integrations/openai_agents/spans/ai_client.py +46 -0
- sentry_sdk/integrations/openai_agents/spans/execute_tool.py +47 -0
- sentry_sdk/integrations/openai_agents/spans/handoff.py +24 -0
- sentry_sdk/integrations/openai_agents/spans/invoke_agent.py +41 -0
- sentry_sdk/integrations/openai_agents/utils.py +201 -0
- sentry_sdk/integrations/openfeature.py +11 -6
- sentry_sdk/integrations/pure_eval.py +6 -10
- sentry_sdk/integrations/pymongo.py +13 -17
- sentry_sdk/integrations/pyramid.py +31 -36
- sentry_sdk/integrations/quart.py +23 -28
- sentry_sdk/integrations/ray.py +73 -64
- sentry_sdk/integrations/redis/__init__.py +7 -4
- sentry_sdk/integrations/redis/_async_common.py +25 -12
- sentry_sdk/integrations/redis/_sync_common.py +19 -13
- sentry_sdk/integrations/redis/modules/caches.py +17 -8
- sentry_sdk/integrations/redis/modules/queries.py +9 -8
- sentry_sdk/integrations/redis/rb.py +3 -2
- sentry_sdk/integrations/redis/redis.py +4 -4
- sentry_sdk/integrations/redis/redis_cluster.py +21 -13
- sentry_sdk/integrations/redis/redis_py_cluster_legacy.py +3 -2
- sentry_sdk/integrations/redis/utils.py +23 -24
- sentry_sdk/integrations/rq.py +13 -16
- sentry_sdk/integrations/rust_tracing.py +9 -6
- sentry_sdk/integrations/sanic.py +34 -46
- sentry_sdk/integrations/serverless.py +22 -27
- sentry_sdk/integrations/socket.py +27 -15
- sentry_sdk/integrations/spark/__init__.py +1 -0
- sentry_sdk/integrations/spark/spark_driver.py +45 -83
- sentry_sdk/integrations/spark/spark_worker.py +7 -11
- sentry_sdk/integrations/sqlalchemy.py +22 -19
- sentry_sdk/integrations/starlette.py +86 -90
- sentry_sdk/integrations/starlite.py +28 -34
- sentry_sdk/integrations/statsig.py +5 -4
- sentry_sdk/integrations/stdlib.py +28 -24
- sentry_sdk/integrations/strawberry.py +62 -49
- sentry_sdk/integrations/sys_exit.py +7 -11
- sentry_sdk/integrations/threading.py +12 -14
- sentry_sdk/integrations/tornado.py +28 -32
- sentry_sdk/integrations/trytond.py +4 -3
- sentry_sdk/integrations/typer.py +8 -6
- sentry_sdk/integrations/unleash.py +5 -4
- sentry_sdk/integrations/wsgi.py +47 -46
- sentry_sdk/logger.py +41 -10
- sentry_sdk/monitor.py +16 -28
- sentry_sdk/opentelemetry/consts.py +11 -4
- sentry_sdk/opentelemetry/contextvars_context.py +26 -16
- sentry_sdk/opentelemetry/propagator.py +38 -21
- sentry_sdk/opentelemetry/sampler.py +51 -34
- sentry_sdk/opentelemetry/scope.py +36 -37
- sentry_sdk/opentelemetry/span_processor.py +48 -58
- sentry_sdk/opentelemetry/tracing.py +58 -14
- sentry_sdk/opentelemetry/utils.py +186 -194
- sentry_sdk/profiler/continuous_profiler.py +108 -97
- sentry_sdk/profiler/transaction_profiler.py +70 -97
- sentry_sdk/profiler/utils.py +11 -15
- sentry_sdk/scope.py +251 -273
- sentry_sdk/scrubber.py +22 -26
- sentry_sdk/serializer.py +40 -54
- sentry_sdk/session.py +44 -61
- sentry_sdk/sessions.py +35 -49
- sentry_sdk/spotlight.py +15 -21
- sentry_sdk/tracing.py +121 -187
- sentry_sdk/tracing_utils.py +104 -122
- sentry_sdk/transport.py +131 -157
- sentry_sdk/utils.py +232 -309
- sentry_sdk/worker.py +16 -28
- {sentry_sdk-3.0.0a1.dist-info → sentry_sdk-3.0.0a3.dist-info}/METADATA +3 -3
- sentry_sdk-3.0.0a3.dist-info/RECORD +168 -0
- {sentry_sdk-3.0.0a1.dist-info → sentry_sdk-3.0.0a3.dist-info}/WHEEL +1 -1
- sentry_sdk-3.0.0a1.dist-info/RECORD +0 -154
- {sentry_sdk-3.0.0a1.dist-info → sentry_sdk-3.0.0a3.dist-info}/entry_points.txt +0 -0
- {sentry_sdk-3.0.0a1.dist-info → sentry_sdk-3.0.0a3.dist-info}/licenses/LICENSE +0 -0
- {sentry_sdk-3.0.0a1.dist-info → sentry_sdk-3.0.0a3.dist-info}/top_level.txt +0 -0
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
1
2
|
import functools
|
|
2
3
|
import os
|
|
3
4
|
import sys
|
|
@@ -40,8 +41,7 @@ if TYPE_CHECKING:
|
|
|
40
41
|
|
|
41
42
|
if getattr(Request, "authenticated_userid", None):
|
|
42
43
|
|
|
43
|
-
def authenticated_userid(request):
|
|
44
|
-
# type: (Request) -> Optional[Any]
|
|
44
|
+
def authenticated_userid(request: Request) -> Optional[Any]:
|
|
45
45
|
return request.authenticated_userid
|
|
46
46
|
|
|
47
47
|
else:
|
|
@@ -58,8 +58,7 @@ class PyramidIntegration(Integration):
|
|
|
58
58
|
|
|
59
59
|
transaction_style = ""
|
|
60
60
|
|
|
61
|
-
def __init__(self, transaction_style="route_name"):
|
|
62
|
-
# type: (str) -> None
|
|
61
|
+
def __init__(self, transaction_style: str = "route_name") -> None:
|
|
63
62
|
if transaction_style not in TRANSACTION_STYLE_VALUES:
|
|
64
63
|
raise ValueError(
|
|
65
64
|
"Invalid value for transaction_style: %s (must be in %s)"
|
|
@@ -68,15 +67,15 @@ class PyramidIntegration(Integration):
|
|
|
68
67
|
self.transaction_style = transaction_style
|
|
69
68
|
|
|
70
69
|
@staticmethod
|
|
71
|
-
def setup_once():
|
|
72
|
-
# type: () -> None
|
|
70
|
+
def setup_once() -> None:
|
|
73
71
|
from pyramid import router
|
|
74
72
|
|
|
75
73
|
old_call_view = router._call_view
|
|
76
74
|
|
|
77
75
|
@functools.wraps(old_call_view)
|
|
78
|
-
def sentry_patched_call_view(
|
|
79
|
-
|
|
76
|
+
def sentry_patched_call_view(
|
|
77
|
+
registry: Any, request: Request, *args: Any, **kwargs: Any
|
|
78
|
+
) -> Response:
|
|
80
79
|
integration = sentry_sdk.get_client().get_integration(PyramidIntegration)
|
|
81
80
|
if integration is None:
|
|
82
81
|
return old_call_view(registry, request, *args, **kwargs)
|
|
@@ -96,8 +95,9 @@ class PyramidIntegration(Integration):
|
|
|
96
95
|
if hasattr(Request, "invoke_exception_view"):
|
|
97
96
|
old_invoke_exception_view = Request.invoke_exception_view
|
|
98
97
|
|
|
99
|
-
def sentry_patched_invoke_exception_view(
|
|
100
|
-
|
|
98
|
+
def sentry_patched_invoke_exception_view(
|
|
99
|
+
self: Request, *args: Any, **kwargs: Any
|
|
100
|
+
) -> Any:
|
|
101
101
|
rv = old_invoke_exception_view(self, *args, **kwargs)
|
|
102
102
|
|
|
103
103
|
if (
|
|
@@ -116,10 +116,12 @@ class PyramidIntegration(Integration):
|
|
|
116
116
|
old_wsgi_call = router.Router.__call__
|
|
117
117
|
|
|
118
118
|
@ensure_integration_enabled(PyramidIntegration, old_wsgi_call)
|
|
119
|
-
def sentry_patched_wsgi_call(
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
119
|
+
def sentry_patched_wsgi_call(
|
|
120
|
+
self: Any, environ: Dict[str, str], start_response: Callable[..., Any]
|
|
121
|
+
) -> _ScopedResponse:
|
|
122
|
+
def sentry_patched_inner_wsgi_call(
|
|
123
|
+
environ: Dict[str, Any], start_response: Callable[..., Any]
|
|
124
|
+
) -> Any:
|
|
123
125
|
try:
|
|
124
126
|
return old_wsgi_call(self, environ, start_response)
|
|
125
127
|
except Exception:
|
|
@@ -137,8 +139,7 @@ class PyramidIntegration(Integration):
|
|
|
137
139
|
|
|
138
140
|
|
|
139
141
|
@ensure_integration_enabled(PyramidIntegration)
|
|
140
|
-
def _capture_exception(exc_info):
|
|
141
|
-
# type: (ExcInfo) -> None
|
|
142
|
+
def _capture_exception(exc_info: ExcInfo) -> None:
|
|
142
143
|
if exc_info[0] is None or issubclass(exc_info[0], HTTPException):
|
|
143
144
|
return
|
|
144
145
|
|
|
@@ -151,8 +152,9 @@ def _capture_exception(exc_info):
|
|
|
151
152
|
sentry_sdk.capture_event(event, hint=hint)
|
|
152
153
|
|
|
153
154
|
|
|
154
|
-
def _set_transaction_name_and_source(
|
|
155
|
-
|
|
155
|
+
def _set_transaction_name_and_source(
|
|
156
|
+
scope: sentry_sdk.Scope, transaction_style: str, request: Request
|
|
157
|
+
) -> None:
|
|
156
158
|
try:
|
|
157
159
|
name_for_style = {
|
|
158
160
|
"route_name": request.matched_route.name,
|
|
@@ -167,40 +169,33 @@ def _set_transaction_name_and_source(scope, transaction_style, request):
|
|
|
167
169
|
|
|
168
170
|
|
|
169
171
|
class PyramidRequestExtractor(RequestExtractor):
|
|
170
|
-
def url(self):
|
|
171
|
-
# type: () -> str
|
|
172
|
+
def url(self) -> str:
|
|
172
173
|
return self.request.path_url
|
|
173
174
|
|
|
174
|
-
def env(self):
|
|
175
|
-
# type: () -> Dict[str, str]
|
|
175
|
+
def env(self) -> Dict[str, str]:
|
|
176
176
|
return self.request.environ
|
|
177
177
|
|
|
178
|
-
def cookies(self):
|
|
179
|
-
# type: () -> RequestCookies
|
|
178
|
+
def cookies(self) -> RequestCookies:
|
|
180
179
|
return self.request.cookies
|
|
181
180
|
|
|
182
|
-
def raw_data(self):
|
|
183
|
-
# type: () -> str
|
|
181
|
+
def raw_data(self) -> str:
|
|
184
182
|
return self.request.text
|
|
185
183
|
|
|
186
|
-
def form(self):
|
|
187
|
-
# type: () -> Dict[str, str]
|
|
184
|
+
def form(self) -> Dict[str, str]:
|
|
188
185
|
return {
|
|
189
186
|
key: value
|
|
190
187
|
for key, value in self.request.POST.items()
|
|
191
188
|
if not getattr(value, "filename", None)
|
|
192
189
|
}
|
|
193
190
|
|
|
194
|
-
def files(self):
|
|
195
|
-
# type: () -> Dict[str, _FieldStorageWithFile]
|
|
191
|
+
def files(self) -> Dict[str, _FieldStorageWithFile]:
|
|
196
192
|
return {
|
|
197
193
|
key: value
|
|
198
194
|
for key, value in self.request.POST.items()
|
|
199
195
|
if getattr(value, "filename", None)
|
|
200
196
|
}
|
|
201
197
|
|
|
202
|
-
def size_of_file(self, postdata):
|
|
203
|
-
# type: (_FieldStorageWithFile) -> int
|
|
198
|
+
def size_of_file(self, postdata: _FieldStorageWithFile) -> int:
|
|
204
199
|
file = postdata.file
|
|
205
200
|
try:
|
|
206
201
|
return os.fstat(file.fileno()).st_size
|
|
@@ -208,10 +203,10 @@ class PyramidRequestExtractor(RequestExtractor):
|
|
|
208
203
|
return 0
|
|
209
204
|
|
|
210
205
|
|
|
211
|
-
def _make_event_processor(
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
206
|
+
def _make_event_processor(
|
|
207
|
+
weak_request: Callable[[], Request], integration: PyramidIntegration
|
|
208
|
+
) -> EventProcessor:
|
|
209
|
+
def pyramid_event_processor(event: Event, hint: Dict[str, Any]) -> Event:
|
|
215
210
|
request = weak_request()
|
|
216
211
|
if request is None:
|
|
217
212
|
return event
|
sentry_sdk/integrations/quart.py
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
1
2
|
import asyncio
|
|
2
3
|
import inspect
|
|
3
4
|
from functools import wraps
|
|
@@ -60,8 +61,7 @@ class QuartIntegration(Integration):
|
|
|
60
61
|
|
|
61
62
|
transaction_style = ""
|
|
62
63
|
|
|
63
|
-
def __init__(self, transaction_style="endpoint"):
|
|
64
|
-
# type: (str) -> None
|
|
64
|
+
def __init__(self, transaction_style: str = "endpoint") -> None:
|
|
65
65
|
if transaction_style not in TRANSACTION_STYLE_VALUES:
|
|
66
66
|
raise ValueError(
|
|
67
67
|
"Invalid value for transaction_style: %s (must be in %s)"
|
|
@@ -70,8 +70,7 @@ class QuartIntegration(Integration):
|
|
|
70
70
|
self.transaction_style = transaction_style
|
|
71
71
|
|
|
72
72
|
@staticmethod
|
|
73
|
-
def setup_once():
|
|
74
|
-
# type: () -> None
|
|
73
|
+
def setup_once() -> None:
|
|
75
74
|
|
|
76
75
|
request_started.connect(_request_websocket_started)
|
|
77
76
|
websocket_started.connect(_request_websocket_started)
|
|
@@ -83,12 +82,12 @@ class QuartIntegration(Integration):
|
|
|
83
82
|
patch_scaffold_route()
|
|
84
83
|
|
|
85
84
|
|
|
86
|
-
def patch_asgi_app():
|
|
87
|
-
# type: () -> None
|
|
85
|
+
def patch_asgi_app() -> None:
|
|
88
86
|
old_app = Quart.__call__
|
|
89
87
|
|
|
90
|
-
async def sentry_patched_asgi_app(
|
|
91
|
-
|
|
88
|
+
async def sentry_patched_asgi_app(
|
|
89
|
+
self: Any, scope: Any, receive: Any, send: Any
|
|
90
|
+
) -> Any:
|
|
92
91
|
if sentry_sdk.get_client().get_integration(QuartIntegration) is None:
|
|
93
92
|
return await old_app(self, scope, receive, send)
|
|
94
93
|
|
|
@@ -102,16 +101,13 @@ def patch_asgi_app():
|
|
|
102
101
|
Quart.__call__ = sentry_patched_asgi_app
|
|
103
102
|
|
|
104
103
|
|
|
105
|
-
def patch_scaffold_route():
|
|
106
|
-
# type: () -> None
|
|
104
|
+
def patch_scaffold_route() -> None:
|
|
107
105
|
old_route = Scaffold.route
|
|
108
106
|
|
|
109
|
-
def _sentry_route(*args, **kwargs):
|
|
110
|
-
# type: (*Any, **Any) -> Any
|
|
107
|
+
def _sentry_route(*args: Any, **kwargs: Any) -> Any:
|
|
111
108
|
old_decorator = old_route(*args, **kwargs)
|
|
112
109
|
|
|
113
|
-
def decorator(old_func):
|
|
114
|
-
# type: (Any) -> Any
|
|
110
|
+
def decorator(old_func: Any) -> Any:
|
|
115
111
|
|
|
116
112
|
if inspect.isfunction(old_func) and not asyncio.iscoroutinefunction(
|
|
117
113
|
old_func
|
|
@@ -119,8 +115,7 @@ def patch_scaffold_route():
|
|
|
119
115
|
|
|
120
116
|
@wraps(old_func)
|
|
121
117
|
@ensure_integration_enabled(QuartIntegration, old_func)
|
|
122
|
-
def _sentry_func(*args, **kwargs):
|
|
123
|
-
# type: (*Any, **Any) -> Any
|
|
118
|
+
def _sentry_func(*args: Any, **kwargs: Any) -> Any:
|
|
124
119
|
current_scope = sentry_sdk.get_current_scope()
|
|
125
120
|
if current_scope.root_span is not None:
|
|
126
121
|
current_scope.root_span.update_active_thread()
|
|
@@ -140,8 +135,9 @@ def patch_scaffold_route():
|
|
|
140
135
|
Scaffold.route = _sentry_route
|
|
141
136
|
|
|
142
137
|
|
|
143
|
-
def _set_transaction_name_and_source(
|
|
144
|
-
|
|
138
|
+
def _set_transaction_name_and_source(
|
|
139
|
+
scope: sentry_sdk.Scope, transaction_style: str, request: Request
|
|
140
|
+
) -> None:
|
|
145
141
|
|
|
146
142
|
try:
|
|
147
143
|
name_for_style = {
|
|
@@ -156,8 +152,7 @@ def _set_transaction_name_and_source(scope, transaction_style, request):
|
|
|
156
152
|
pass
|
|
157
153
|
|
|
158
154
|
|
|
159
|
-
async def _request_websocket_started(app, **kwargs):
|
|
160
|
-
# type: (Quart, **Any) -> None
|
|
155
|
+
async def _request_websocket_started(app: Quart, **kwargs: Any) -> None:
|
|
161
156
|
integration = sentry_sdk.get_client().get_integration(QuartIntegration)
|
|
162
157
|
if integration is None:
|
|
163
158
|
return
|
|
@@ -178,10 +173,10 @@ async def _request_websocket_started(app, **kwargs):
|
|
|
178
173
|
scope.add_event_processor(evt_processor)
|
|
179
174
|
|
|
180
175
|
|
|
181
|
-
def _make_request_event_processor(
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
176
|
+
def _make_request_event_processor(
|
|
177
|
+
app: Quart, request: Request, integration: QuartIntegration
|
|
178
|
+
) -> EventProcessor:
|
|
179
|
+
def inner(event: Event, hint: dict[str, Any]) -> Event:
|
|
185
180
|
# if the request is gone we are fine not logging the data from
|
|
186
181
|
# it. This might happen if the processor is pushed away to
|
|
187
182
|
# another thread.
|
|
@@ -207,8 +202,9 @@ def _make_request_event_processor(app, request, integration):
|
|
|
207
202
|
return inner
|
|
208
203
|
|
|
209
204
|
|
|
210
|
-
async def _capture_exception(
|
|
211
|
-
|
|
205
|
+
async def _capture_exception(
|
|
206
|
+
sender: Quart, exception: Union[ValueError, BaseException], **kwargs: Any
|
|
207
|
+
) -> None:
|
|
212
208
|
integration = sentry_sdk.get_client().get_integration(QuartIntegration)
|
|
213
209
|
if integration is None:
|
|
214
210
|
return
|
|
@@ -222,8 +218,7 @@ async def _capture_exception(sender, exception, **kwargs):
|
|
|
222
218
|
sentry_sdk.capture_event(event, hint=hint)
|
|
223
219
|
|
|
224
220
|
|
|
225
|
-
def _add_user_to_event(event):
|
|
226
|
-
# type: (Event) -> None
|
|
221
|
+
def _add_user_to_event(event: Event) -> None:
|
|
227
222
|
if quart_auth is None:
|
|
228
223
|
return
|
|
229
224
|
|
sentry_sdk/integrations/ray.py
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
1
2
|
import inspect
|
|
2
3
|
import sys
|
|
3
4
|
|
|
@@ -29,8 +30,7 @@ if TYPE_CHECKING:
|
|
|
29
30
|
DEFAULT_TRANSACTION_NAME = "unknown Ray function"
|
|
30
31
|
|
|
31
32
|
|
|
32
|
-
def _check_sentry_initialized():
|
|
33
|
-
# type: () -> None
|
|
33
|
+
def _check_sentry_initialized() -> None:
|
|
34
34
|
if sentry_sdk.get_client().is_active():
|
|
35
35
|
return
|
|
36
36
|
|
|
@@ -39,88 +39,98 @@ def _check_sentry_initialized():
|
|
|
39
39
|
)
|
|
40
40
|
|
|
41
41
|
|
|
42
|
-
def _patch_ray_remote():
|
|
43
|
-
# type: () -> None
|
|
42
|
+
def _patch_ray_remote() -> None:
|
|
44
43
|
old_remote = ray.remote
|
|
45
44
|
|
|
46
45
|
@functools.wraps(old_remote)
|
|
47
|
-
def new_remote(
|
|
48
|
-
|
|
46
|
+
def new_remote(
|
|
47
|
+
f: Optional[Callable[..., Any]] = None, *args: Any, **kwargs: Any
|
|
48
|
+
) -> Callable[..., Any]:
|
|
49
|
+
|
|
49
50
|
if inspect.isclass(f):
|
|
50
51
|
# Ray Actors
|
|
51
52
|
# (https://docs.ray.io/en/latest/ray-core/actors.html)
|
|
52
53
|
# are not supported
|
|
53
54
|
# (Only Ray Tasks are supported)
|
|
54
|
-
return old_remote(f, *args,
|
|
55
|
-
|
|
56
|
-
def
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
55
|
+
return old_remote(f, *args, **kwargs)
|
|
56
|
+
|
|
57
|
+
def wrapper(user_f: Callable[..., Any]) -> Any:
|
|
58
|
+
def new_func(
|
|
59
|
+
*f_args: Any, _tracing: Optional[dict[str, Any]] = None, **f_kwargs: Any
|
|
60
|
+
) -> Any:
|
|
61
|
+
_check_sentry_initialized()
|
|
62
|
+
|
|
63
|
+
root_span_name = (
|
|
64
|
+
qualname_from_function(user_f) or DEFAULT_TRANSACTION_NAME
|
|
65
|
+
)
|
|
66
|
+
sentry_sdk.get_current_scope().set_transaction_name(
|
|
67
|
+
root_span_name,
|
|
68
|
+
source=TransactionSource.TASK,
|
|
69
|
+
)
|
|
70
|
+
with sentry_sdk.continue_trace(_tracing or {}):
|
|
71
|
+
with sentry_sdk.start_span(
|
|
72
|
+
op=OP.QUEUE_TASK_RAY,
|
|
73
|
+
name=qualname_from_function(user_f),
|
|
74
|
+
origin=RayIntegration.origin,
|
|
75
|
+
source=TransactionSource.TASK,
|
|
76
|
+
) as root_span:
|
|
77
|
+
try:
|
|
78
|
+
result = user_f(*f_args, **f_kwargs)
|
|
79
|
+
root_span.set_status(SPANSTATUS.OK)
|
|
80
|
+
except Exception:
|
|
81
|
+
root_span.set_status(SPANSTATUS.INTERNAL_ERROR)
|
|
82
|
+
exc_info = sys.exc_info()
|
|
83
|
+
_capture_exception(exc_info)
|
|
84
|
+
reraise(*exc_info)
|
|
85
|
+
|
|
86
|
+
return result
|
|
87
|
+
|
|
88
|
+
if f:
|
|
89
|
+
rv = old_remote(new_func)
|
|
90
|
+
else:
|
|
91
|
+
rv = old_remote(*args, **kwargs)(new_func)
|
|
92
|
+
old_remote_method = rv.remote
|
|
93
|
+
|
|
94
|
+
def _remote_method_with_header_propagation(
|
|
95
|
+
*args: Any, **kwargs: Any
|
|
96
|
+
) -> Any:
|
|
97
|
+
"""
|
|
98
|
+
Ray Client
|
|
99
|
+
"""
|
|
69
100
|
with sentry_sdk.start_span(
|
|
70
|
-
op=OP.
|
|
71
|
-
name=
|
|
101
|
+
op=OP.QUEUE_SUBMIT_RAY,
|
|
102
|
+
name=qualname_from_function(user_f),
|
|
72
103
|
origin=RayIntegration.origin,
|
|
73
|
-
|
|
74
|
-
) as
|
|
104
|
+
only_if_parent=True,
|
|
105
|
+
) as span:
|
|
106
|
+
tracing = {
|
|
107
|
+
k: v
|
|
108
|
+
for k, v in sentry_sdk.get_current_scope().iter_trace_propagation_headers()
|
|
109
|
+
}
|
|
75
110
|
try:
|
|
76
|
-
result =
|
|
77
|
-
|
|
111
|
+
result = old_remote_method(*args, **kwargs, _tracing=tracing)
|
|
112
|
+
span.set_status(SPANSTATUS.OK)
|
|
78
113
|
except Exception:
|
|
79
|
-
|
|
114
|
+
span.set_status(SPANSTATUS.INTERNAL_ERROR)
|
|
80
115
|
exc_info = sys.exc_info()
|
|
81
116
|
_capture_exception(exc_info)
|
|
82
117
|
reraise(*exc_info)
|
|
83
118
|
|
|
84
119
|
return result
|
|
85
120
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
with sentry_sdk.start_span(
|
|
95
|
-
op=OP.QUEUE_SUBMIT_RAY,
|
|
96
|
-
name=qualname_from_function(f),
|
|
97
|
-
origin=RayIntegration.origin,
|
|
98
|
-
only_if_parent=True,
|
|
99
|
-
) as span:
|
|
100
|
-
tracing = {
|
|
101
|
-
k: v
|
|
102
|
-
for k, v in sentry_sdk.get_current_scope().iter_trace_propagation_headers()
|
|
103
|
-
}
|
|
104
|
-
try:
|
|
105
|
-
result = old_remote_method(*args, **kwargs, _tracing=tracing)
|
|
106
|
-
span.set_status(SPANSTATUS.OK)
|
|
107
|
-
except Exception:
|
|
108
|
-
span.set_status(SPANSTATUS.INTERNAL_ERROR)
|
|
109
|
-
exc_info = sys.exc_info()
|
|
110
|
-
_capture_exception(exc_info)
|
|
111
|
-
reraise(*exc_info)
|
|
112
|
-
|
|
113
|
-
return result
|
|
114
|
-
|
|
115
|
-
rv.remote = _remote_method_with_header_propagation
|
|
116
|
-
|
|
117
|
-
return rv
|
|
121
|
+
rv.remote = _remote_method_with_header_propagation
|
|
122
|
+
|
|
123
|
+
return rv
|
|
124
|
+
|
|
125
|
+
if f is not None:
|
|
126
|
+
return wrapper(f)
|
|
127
|
+
else:
|
|
128
|
+
return wrapper
|
|
118
129
|
|
|
119
130
|
ray.remote = new_remote
|
|
120
131
|
|
|
121
132
|
|
|
122
|
-
def _capture_exception(exc_info, **kwargs):
|
|
123
|
-
# type: (ExcInfo, **Any) -> None
|
|
133
|
+
def _capture_exception(exc_info: ExcInfo, **kwargs: Any) -> None:
|
|
124
134
|
client = sentry_sdk.get_client()
|
|
125
135
|
|
|
126
136
|
event, hint = event_from_exception(
|
|
@@ -139,8 +149,7 @@ class RayIntegration(Integration):
|
|
|
139
149
|
origin = f"auto.queue.{identifier}"
|
|
140
150
|
|
|
141
151
|
@staticmethod
|
|
142
|
-
def setup_once():
|
|
143
|
-
# type: () -> None
|
|
152
|
+
def setup_once() -> None:
|
|
144
153
|
version = package_version("ray")
|
|
145
154
|
_check_minimum_version(RayIntegration, version)
|
|
146
155
|
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
1
2
|
from sentry_sdk.integrations import Integration, DidNotEnable
|
|
2
3
|
from sentry_sdk.integrations.redis.consts import _DEFAULT_MAX_DATA_SIZE
|
|
3
4
|
from sentry_sdk.integrations.redis.rb import _patch_rb
|
|
@@ -15,14 +16,16 @@ if TYPE_CHECKING:
|
|
|
15
16
|
class RedisIntegration(Integration):
|
|
16
17
|
identifier = "redis"
|
|
17
18
|
|
|
18
|
-
def __init__(
|
|
19
|
-
|
|
19
|
+
def __init__(
|
|
20
|
+
self,
|
|
21
|
+
max_data_size: int = _DEFAULT_MAX_DATA_SIZE,
|
|
22
|
+
cache_prefixes: Optional[list[str]] = None,
|
|
23
|
+
) -> None:
|
|
20
24
|
self.max_data_size = max_data_size
|
|
21
25
|
self.cache_prefixes = cache_prefixes if cache_prefixes is not None else []
|
|
22
26
|
|
|
23
27
|
@staticmethod
|
|
24
|
-
def setup_once():
|
|
25
|
-
# type: () -> None
|
|
28
|
+
def setup_once() -> None:
|
|
26
29
|
try:
|
|
27
30
|
from redis import StrictRedis, client
|
|
28
31
|
except ImportError:
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
1
2
|
import sentry_sdk
|
|
2
3
|
from sentry_sdk.consts import OP
|
|
3
4
|
from sentry_sdk.integrations.redis.consts import SPAN_ORIGIN
|
|
@@ -24,15 +25,16 @@ if TYPE_CHECKING:
|
|
|
24
25
|
|
|
25
26
|
|
|
26
27
|
def patch_redis_async_pipeline(
|
|
27
|
-
pipeline_cls
|
|
28
|
-
|
|
29
|
-
|
|
28
|
+
pipeline_cls: Union[type[Pipeline[Any]], type[ClusterPipeline[Any]]],
|
|
29
|
+
is_cluster: bool,
|
|
30
|
+
get_command_args_fn: Any,
|
|
31
|
+
get_db_data_fn: Callable[[Any], dict[str, Any]],
|
|
32
|
+
) -> None:
|
|
30
33
|
old_execute = pipeline_cls.execute
|
|
31
34
|
|
|
32
35
|
from sentry_sdk.integrations.redis import RedisIntegration
|
|
33
36
|
|
|
34
|
-
async def _sentry_execute(self, *args, **kwargs):
|
|
35
|
-
# type: (Any, *Any, **Any) -> Any
|
|
37
|
+
async def _sentry_execute(self: Any, *args: Any, **kwargs: Any) -> Any:
|
|
36
38
|
if sentry_sdk.get_client().get_integration(RedisIntegration) is None:
|
|
37
39
|
return await old_execute(self, *args, **kwargs)
|
|
38
40
|
|
|
@@ -44,13 +46,20 @@ def patch_redis_async_pipeline(
|
|
|
44
46
|
) as span:
|
|
45
47
|
with capture_internal_exceptions():
|
|
46
48
|
span_data = get_db_data_fn(self)
|
|
49
|
+
|
|
50
|
+
try:
|
|
51
|
+
command_seq = self._execution_strategy._command_queue
|
|
52
|
+
except AttributeError:
|
|
53
|
+
if is_cluster:
|
|
54
|
+
command_seq = self._command_stack
|
|
55
|
+
else:
|
|
56
|
+
command_seq = self.command_stack
|
|
57
|
+
|
|
47
58
|
pipeline_data = _get_pipeline_data(
|
|
48
59
|
is_cluster=is_cluster,
|
|
49
60
|
get_command_args_fn=get_command_args_fn,
|
|
50
61
|
is_transaction=False if is_cluster else self.is_transaction,
|
|
51
|
-
|
|
52
|
-
self._command_stack if is_cluster else self.command_stack
|
|
53
|
-
),
|
|
62
|
+
command_seq=command_seq,
|
|
54
63
|
)
|
|
55
64
|
_update_span(span, span_data, pipeline_data)
|
|
56
65
|
_create_breadcrumb("redis.pipeline.execute", span_data, pipeline_data)
|
|
@@ -60,14 +69,18 @@ def patch_redis_async_pipeline(
|
|
|
60
69
|
pipeline_cls.execute = _sentry_execute # type: ignore
|
|
61
70
|
|
|
62
71
|
|
|
63
|
-
def patch_redis_async_client(
|
|
64
|
-
|
|
72
|
+
def patch_redis_async_client(
|
|
73
|
+
cls: Union[type[StrictRedis[Any]], type[RedisCluster[Any]]],
|
|
74
|
+
is_cluster: bool,
|
|
75
|
+
get_db_data_fn: Callable[[Any], dict[str, Any]],
|
|
76
|
+
) -> None:
|
|
65
77
|
old_execute_command = cls.execute_command
|
|
66
78
|
|
|
67
79
|
from sentry_sdk.integrations.redis import RedisIntegration
|
|
68
80
|
|
|
69
|
-
async def _sentry_execute_command(
|
|
70
|
-
|
|
81
|
+
async def _sentry_execute_command(
|
|
82
|
+
self: Any, name: str, *args: Any, **kwargs: Any
|
|
83
|
+
) -> Any:
|
|
71
84
|
integration = sentry_sdk.get_client().get_integration(RedisIntegration)
|
|
72
85
|
if integration is None:
|
|
73
86
|
return await old_execute_command(self, name, *args, **kwargs)
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
1
2
|
import sentry_sdk
|
|
2
3
|
from sentry_sdk.consts import OP
|
|
3
4
|
from sentry_sdk.integrations.redis.consts import SPAN_ORIGIN
|
|
@@ -22,18 +23,16 @@ if TYPE_CHECKING:
|
|
|
22
23
|
|
|
23
24
|
|
|
24
25
|
def patch_redis_pipeline(
|
|
25
|
-
pipeline_cls,
|
|
26
|
-
is_cluster,
|
|
27
|
-
get_command_args_fn,
|
|
28
|
-
get_db_data_fn,
|
|
29
|
-
):
|
|
30
|
-
# type: (Any, bool, Any, Callable[[Any], dict[str, Any]]) -> None
|
|
26
|
+
pipeline_cls: Any,
|
|
27
|
+
is_cluster: bool,
|
|
28
|
+
get_command_args_fn: Any,
|
|
29
|
+
get_db_data_fn: Callable[[Any], dict[str, Any]],
|
|
30
|
+
) -> None:
|
|
31
31
|
old_execute = pipeline_cls.execute
|
|
32
32
|
|
|
33
33
|
from sentry_sdk.integrations.redis import RedisIntegration
|
|
34
34
|
|
|
35
|
-
def sentry_patched_execute(self, *args, **kwargs):
|
|
36
|
-
# type: (Any, *Any, **Any) -> Any
|
|
35
|
+
def sentry_patched_execute(self: Any, *args: Any, **kwargs: Any) -> Any:
|
|
37
36
|
if sentry_sdk.get_client().get_integration(RedisIntegration) is None:
|
|
38
37
|
return old_execute(self, *args, **kwargs)
|
|
39
38
|
|
|
@@ -44,12 +43,17 @@ def patch_redis_pipeline(
|
|
|
44
43
|
only_if_parent=True,
|
|
45
44
|
) as span:
|
|
46
45
|
with capture_internal_exceptions():
|
|
46
|
+
try:
|
|
47
|
+
command_seq = self._execution_strategy.command_queue
|
|
48
|
+
except AttributeError:
|
|
49
|
+
command_seq = self.command_stack
|
|
50
|
+
|
|
47
51
|
span_data = get_db_data_fn(self)
|
|
48
52
|
pipeline_data = _get_pipeline_data(
|
|
49
53
|
is_cluster=is_cluster,
|
|
50
54
|
get_command_args_fn=get_command_args_fn,
|
|
51
55
|
is_transaction=False if is_cluster else self.transaction,
|
|
52
|
-
|
|
56
|
+
command_seq=command_seq,
|
|
53
57
|
)
|
|
54
58
|
_update_span(span, span_data, pipeline_data)
|
|
55
59
|
_create_breadcrumb("redis.pipeline.execute", span_data, pipeline_data)
|
|
@@ -59,8 +63,9 @@ def patch_redis_pipeline(
|
|
|
59
63
|
pipeline_cls.execute = sentry_patched_execute
|
|
60
64
|
|
|
61
65
|
|
|
62
|
-
def patch_redis_client(
|
|
63
|
-
|
|
66
|
+
def patch_redis_client(
|
|
67
|
+
cls: Any, is_cluster: bool, get_db_data_fn: Callable[[Any], dict[str, Any]]
|
|
68
|
+
) -> None:
|
|
64
69
|
"""
|
|
65
70
|
This function can be used to instrument custom redis client classes or
|
|
66
71
|
subclasses.
|
|
@@ -69,8 +74,9 @@ def patch_redis_client(cls, is_cluster, get_db_data_fn):
|
|
|
69
74
|
|
|
70
75
|
from sentry_sdk.integrations.redis import RedisIntegration
|
|
71
76
|
|
|
72
|
-
def sentry_patched_execute_command(
|
|
73
|
-
|
|
77
|
+
def sentry_patched_execute_command(
|
|
78
|
+
self: Any, name: str, *args: Any, **kwargs: Any
|
|
79
|
+
) -> Any:
|
|
74
80
|
integration = sentry_sdk.get_client().get_integration(RedisIntegration)
|
|
75
81
|
if integration is None:
|
|
76
82
|
return old_execute_command(self, name, *args, **kwargs)
|