sentry-sdk 3.0.0a2__py2.py3-none-any.whl → 3.0.0a4__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 +4 -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 +9 -16
- sentry_sdk/_werkzeug.py +5 -7
- sentry_sdk/ai/monitoring.py +45 -33
- sentry_sdk/ai/utils.py +8 -5
- sentry_sdk/api.py +91 -87
- sentry_sdk/attachments.py +10 -12
- sentry_sdk/client.py +119 -159
- sentry_sdk/consts.py +432 -223
- 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 +16 -18
- sentry_sdk/integrations/_wsgi_common.py +22 -33
- sentry_sdk/integrations/aiohttp.py +33 -31
- sentry_sdk/integrations/anthropic.py +43 -38
- sentry_sdk/integrations/argv.py +3 -4
- sentry_sdk/integrations/ariadne.py +16 -18
- sentry_sdk/integrations/arq.py +20 -29
- sentry_sdk/integrations/asgi.py +63 -37
- sentry_sdk/integrations/asyncio.py +15 -17
- sentry_sdk/integrations/asyncpg.py +1 -1
- 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 +20 -18
- sentry_sdk/integrations/bottle.py +25 -34
- sentry_sdk/integrations/celery/__init__.py +40 -59
- sentry_sdk/integrations/celery/beat.py +22 -26
- sentry_sdk/integrations/celery/utils.py +15 -17
- sentry_sdk/integrations/chalice.py +8 -10
- sentry_sdk/integrations/clickhouse_driver.py +22 -32
- sentry_sdk/integrations/cloud_resource_context.py +9 -16
- sentry_sdk/integrations/cohere.py +19 -25
- sentry_sdk/integrations/dedupe.py +5 -8
- sentry_sdk/integrations/django/__init__.py +69 -74
- sentry_sdk/integrations/django/asgi.py +25 -33
- sentry_sdk/integrations/django/caching.py +24 -20
- sentry_sdk/integrations/django/middleware.py +18 -21
- sentry_sdk/integrations/django/signals_handlers.py +12 -11
- sentry_sdk/integrations/django/templates.py +21 -18
- sentry_sdk/integrations/django/transactions.py +16 -11
- sentry_sdk/integrations/django/views.py +8 -12
- 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 +7 -20
- sentry_sdk/integrations/gql.py +16 -17
- sentry_sdk/integrations/graphene.py +14 -13
- sentry_sdk/integrations/grpc/__init__.py +3 -2
- sentry_sdk/integrations/grpc/aio/client.py +2 -2
- sentry_sdk/integrations/grpc/aio/server.py +15 -14
- sentry_sdk/integrations/grpc/client.py +21 -11
- sentry_sdk/integrations/grpc/consts.py +2 -0
- sentry_sdk/integrations/grpc/server.py +12 -8
- sentry_sdk/integrations/httpx.py +11 -14
- sentry_sdk/integrations/huey.py +14 -21
- sentry_sdk/integrations/huggingface_hub.py +17 -17
- sentry_sdk/integrations/langchain.py +204 -114
- sentry_sdk/integrations/launchdarkly.py +13 -10
- sentry_sdk/integrations/litestar.py +40 -38
- sentry_sdk/integrations/logging.py +29 -36
- sentry_sdk/integrations/loguru.py +16 -20
- sentry_sdk/integrations/modules.py +3 -4
- sentry_sdk/integrations/openai.py +421 -204
- 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 +153 -0
- sentry_sdk/integrations/openfeature.py +12 -8
- sentry_sdk/integrations/pure_eval.py +6 -10
- sentry_sdk/integrations/pymongo.py +14 -18
- 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 +18 -12
- sentry_sdk/integrations/redis/_sync_common.py +16 -15
- 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 +10 -8
- sentry_sdk/integrations/redis/redis_py_cluster_legacy.py +3 -2
- sentry_sdk/integrations/redis/utils.py +21 -22
- sentry_sdk/integrations/rq.py +13 -16
- sentry_sdk/integrations/rust_tracing.py +10 -7
- sentry_sdk/integrations/sanic.py +34 -46
- sentry_sdk/integrations/serverless.py +22 -27
- sentry_sdk/integrations/socket.py +29 -17
- 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 +89 -93
- sentry_sdk/integrations/starlite.py +31 -37
- sentry_sdk/integrations/statsig.py +5 -4
- sentry_sdk/integrations/stdlib.py +32 -28
- sentry_sdk/integrations/strawberry.py +63 -50
- sentry_sdk/integrations/sys_exit.py +7 -11
- sentry_sdk/integrations/threading.py +13 -15
- 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 +13 -9
- sentry_sdk/monitor.py +16 -28
- sentry_sdk/opentelemetry/consts.py +11 -4
- sentry_sdk/opentelemetry/contextvars_context.py +17 -15
- sentry_sdk/opentelemetry/propagator.py +38 -21
- sentry_sdk/opentelemetry/sampler.py +51 -34
- sentry_sdk/opentelemetry/scope.py +46 -37
- sentry_sdk/opentelemetry/span_processor.py +43 -59
- sentry_sdk/opentelemetry/tracing.py +32 -12
- sentry_sdk/opentelemetry/utils.py +180 -196
- 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 -264
- sentry_sdk/scrubber.py +22 -26
- sentry_sdk/serializer.py +48 -65
- sentry_sdk/session.py +44 -61
- sentry_sdk/sessions.py +35 -49
- sentry_sdk/spotlight.py +15 -21
- sentry_sdk/tracing.py +118 -184
- sentry_sdk/tracing_utils.py +103 -123
- sentry_sdk/transport.py +131 -157
- sentry_sdk/utils.py +278 -309
- sentry_sdk/worker.py +16 -28
- {sentry_sdk-3.0.0a2.dist-info → sentry_sdk-3.0.0a4.dist-info}/METADATA +1 -1
- sentry_sdk-3.0.0a4.dist-info/RECORD +168 -0
- sentry_sdk-3.0.0a2.dist-info/RECORD +0 -154
- {sentry_sdk-3.0.0a2.dist-info → sentry_sdk-3.0.0a4.dist-info}/WHEEL +0 -0
- {sentry_sdk-3.0.0a2.dist-info → sentry_sdk-3.0.0a4.dist-info}/entry_points.txt +0 -0
- {sentry_sdk-3.0.0a2.dist-info → sentry_sdk-3.0.0a4.dist-info}/licenses/LICENSE +0 -0
- {sentry_sdk-3.0.0a2.dist-info → sentry_sdk-3.0.0a4.dist-info}/top_level.txt +0 -0
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
1
2
|
import sentry_sdk
|
|
2
3
|
from sentry_sdk.consts import SOURCE_FOR_STYLE
|
|
3
4
|
from sentry_sdk.integrations import _check_minimum_version, Integration, DidNotEnable
|
|
@@ -33,30 +34,25 @@ falcon_helpers = falcon.app_helpers
|
|
|
33
34
|
falcon_app_class = falcon.App
|
|
34
35
|
|
|
35
36
|
|
|
36
|
-
_FALCON_UNSET
|
|
37
|
+
_FALCON_UNSET: Optional[object] = None
|
|
37
38
|
with capture_internal_exceptions():
|
|
38
39
|
from falcon.request import _UNSET as _FALCON_UNSET # type: ignore[import-not-found, no-redef]
|
|
39
40
|
|
|
40
41
|
|
|
41
42
|
class FalconRequestExtractor(RequestExtractor):
|
|
42
|
-
def env(self):
|
|
43
|
-
# type: () -> Dict[str, Any]
|
|
43
|
+
def env(self) -> Dict[str, Any]:
|
|
44
44
|
return self.request.env
|
|
45
45
|
|
|
46
|
-
def cookies(self):
|
|
47
|
-
# type: () -> Dict[str, Any]
|
|
46
|
+
def cookies(self) -> Dict[str, Any]:
|
|
48
47
|
return self.request.cookies
|
|
49
48
|
|
|
50
|
-
def form(self):
|
|
51
|
-
# type: () -> None
|
|
49
|
+
def form(self) -> None:
|
|
52
50
|
return None # No such concept in Falcon
|
|
53
51
|
|
|
54
|
-
def files(self):
|
|
55
|
-
# type: () -> None
|
|
52
|
+
def files(self) -> None:
|
|
56
53
|
return None # No such concept in Falcon
|
|
57
54
|
|
|
58
|
-
def raw_data(self):
|
|
59
|
-
# type: () -> Optional[str]
|
|
55
|
+
def raw_data(self) -> Optional[str]:
|
|
60
56
|
|
|
61
57
|
# As request data can only be read once we won't make this available
|
|
62
58
|
# to Sentry. Just send back a dummy string in case there was a
|
|
@@ -68,8 +64,7 @@ class FalconRequestExtractor(RequestExtractor):
|
|
|
68
64
|
else:
|
|
69
65
|
return None
|
|
70
66
|
|
|
71
|
-
def json(self):
|
|
72
|
-
# type: () -> Optional[Dict[str, Any]]
|
|
67
|
+
def json(self) -> Optional[Dict[str, Any]]:
|
|
73
68
|
# fallback to cached_media = None if self.request._media is not available
|
|
74
69
|
cached_media = None
|
|
75
70
|
with capture_internal_exceptions():
|
|
@@ -90,8 +85,7 @@ class FalconRequestExtractor(RequestExtractor):
|
|
|
90
85
|
class SentryFalconMiddleware:
|
|
91
86
|
"""Captures exceptions in Falcon requests and send to Sentry"""
|
|
92
87
|
|
|
93
|
-
def process_request(self, req, resp, *args, **kwargs):
|
|
94
|
-
# type: (Any, Any, *Any, **Any) -> None
|
|
88
|
+
def process_request(self, req: Any, resp: Any, *args: Any, **kwargs: Any) -> None:
|
|
95
89
|
integration = sentry_sdk.get_client().get_integration(FalconIntegration)
|
|
96
90
|
if integration is None:
|
|
97
91
|
return
|
|
@@ -110,8 +104,7 @@ class FalconIntegration(Integration):
|
|
|
110
104
|
|
|
111
105
|
transaction_style = ""
|
|
112
106
|
|
|
113
|
-
def __init__(self, transaction_style="uri_template"):
|
|
114
|
-
# type: (str) -> None
|
|
107
|
+
def __init__(self, transaction_style: str = "uri_template") -> None:
|
|
115
108
|
if transaction_style not in TRANSACTION_STYLE_VALUES:
|
|
116
109
|
raise ValueError(
|
|
117
110
|
"Invalid value for transaction_style: %s (must be in %s)"
|
|
@@ -120,8 +113,7 @@ class FalconIntegration(Integration):
|
|
|
120
113
|
self.transaction_style = transaction_style
|
|
121
114
|
|
|
122
115
|
@staticmethod
|
|
123
|
-
def setup_once():
|
|
124
|
-
# type: () -> None
|
|
116
|
+
def setup_once() -> None:
|
|
125
117
|
|
|
126
118
|
version = parse_version(FALCON_VERSION)
|
|
127
119
|
_check_minimum_version(FalconIntegration, version)
|
|
@@ -131,12 +123,10 @@ class FalconIntegration(Integration):
|
|
|
131
123
|
_patch_prepare_middleware()
|
|
132
124
|
|
|
133
125
|
|
|
134
|
-
def _patch_wsgi_app():
|
|
135
|
-
# type: () -> None
|
|
126
|
+
def _patch_wsgi_app() -> None:
|
|
136
127
|
original_wsgi_app = falcon_app_class.__call__
|
|
137
128
|
|
|
138
|
-
def sentry_patched_wsgi_app(self, env, start_response):
|
|
139
|
-
# type: (falcon.API, Any, Any) -> Any
|
|
129
|
+
def sentry_patched_wsgi_app(self: falcon.API, env: Any, start_response: Any) -> Any:
|
|
140
130
|
integration = sentry_sdk.get_client().get_integration(FalconIntegration)
|
|
141
131
|
if integration is None:
|
|
142
132
|
return original_wsgi_app(self, env, start_response)
|
|
@@ -151,13 +141,11 @@ def _patch_wsgi_app():
|
|
|
151
141
|
falcon_app_class.__call__ = sentry_patched_wsgi_app
|
|
152
142
|
|
|
153
143
|
|
|
154
|
-
def _patch_handle_exception():
|
|
155
|
-
# type: () -> None
|
|
144
|
+
def _patch_handle_exception() -> None:
|
|
156
145
|
original_handle_exception = falcon_app_class._handle_exception
|
|
157
146
|
|
|
158
147
|
@ensure_integration_enabled(FalconIntegration, original_handle_exception)
|
|
159
|
-
def sentry_patched_handle_exception(self, *args):
|
|
160
|
-
# type: (falcon.API, *Any) -> Any
|
|
148
|
+
def sentry_patched_handle_exception(self: falcon.API, *args: Any) -> Any:
|
|
161
149
|
# NOTE(jmagnusson): falcon 2.0 changed falcon.API._handle_exception
|
|
162
150
|
# method signature from `(ex, req, resp, params)` to
|
|
163
151
|
# `(req, resp, ex, params)`
|
|
@@ -189,14 +177,12 @@ def _patch_handle_exception():
|
|
|
189
177
|
falcon_app_class._handle_exception = sentry_patched_handle_exception
|
|
190
178
|
|
|
191
179
|
|
|
192
|
-
def _patch_prepare_middleware():
|
|
193
|
-
# type: () -> None
|
|
180
|
+
def _patch_prepare_middleware() -> None:
|
|
194
181
|
original_prepare_middleware = falcon_helpers.prepare_middleware
|
|
195
182
|
|
|
196
183
|
def sentry_patched_prepare_middleware(
|
|
197
|
-
middleware=None, independent_middleware=False, asgi=False
|
|
198
|
-
):
|
|
199
|
-
# type: (Any, Any, bool) -> Any
|
|
184
|
+
middleware: Any = None, independent_middleware: Any = False, asgi: bool = False
|
|
185
|
+
) -> Any:
|
|
200
186
|
if asgi:
|
|
201
187
|
# We don't support ASGI Falcon apps, so we don't patch anything here
|
|
202
188
|
return original_prepare_middleware(middleware, independent_middleware, asgi)
|
|
@@ -212,8 +198,7 @@ def _patch_prepare_middleware():
|
|
|
212
198
|
falcon_helpers.prepare_middleware = sentry_patched_prepare_middleware
|
|
213
199
|
|
|
214
200
|
|
|
215
|
-
def _exception_leads_to_http_5xx(ex, response):
|
|
216
|
-
# type: (Exception, falcon.Response) -> bool
|
|
201
|
+
def _exception_leads_to_http_5xx(ex: Exception, response: falcon.Response) -> bool:
|
|
217
202
|
is_server_error = isinstance(ex, falcon.HTTPError) and (ex.status or "").startswith(
|
|
218
203
|
"5"
|
|
219
204
|
)
|
|
@@ -224,13 +209,13 @@ def _exception_leads_to_http_5xx(ex, response):
|
|
|
224
209
|
return (is_server_error or is_unhandled_error) and _has_http_5xx_status(response)
|
|
225
210
|
|
|
226
211
|
|
|
227
|
-
def _has_http_5xx_status(response):
|
|
228
|
-
# type: (falcon.Response) -> bool
|
|
212
|
+
def _has_http_5xx_status(response: falcon.Response) -> bool:
|
|
229
213
|
return response.status.startswith("5")
|
|
230
214
|
|
|
231
215
|
|
|
232
|
-
def _set_transaction_name_and_source(
|
|
233
|
-
|
|
216
|
+
def _set_transaction_name_and_source(
|
|
217
|
+
event: Event, transaction_style: str, request: falcon.Request
|
|
218
|
+
) -> None:
|
|
234
219
|
name_for_style = {
|
|
235
220
|
"uri_template": request.uri_template,
|
|
236
221
|
"path": request.path,
|
|
@@ -239,11 +224,11 @@ def _set_transaction_name_and_source(event, transaction_style, request):
|
|
|
239
224
|
event["transaction_info"] = {"source": SOURCE_FOR_STYLE[transaction_style]}
|
|
240
225
|
|
|
241
226
|
|
|
242
|
-
def _make_request_event_processor(
|
|
243
|
-
|
|
227
|
+
def _make_request_event_processor(
|
|
228
|
+
req: falcon.Request, integration: FalconIntegration
|
|
229
|
+
) -> EventProcessor:
|
|
244
230
|
|
|
245
|
-
def event_processor(event, hint):
|
|
246
|
-
# type: (Event, dict[str, Any]) -> Event
|
|
231
|
+
def event_processor(event: Event, hint: dict[str, Any]) -> Event:
|
|
247
232
|
_set_transaction_name_and_source(event, integration.transaction_style, req)
|
|
248
233
|
|
|
249
234
|
with capture_internal_exceptions():
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
1
2
|
import asyncio
|
|
2
3
|
from copy import deepcopy
|
|
3
4
|
from functools import wraps
|
|
@@ -38,13 +39,13 @@ class FastApiIntegration(StarletteIntegration):
|
|
|
38
39
|
identifier = "fastapi"
|
|
39
40
|
|
|
40
41
|
@staticmethod
|
|
41
|
-
def setup_once():
|
|
42
|
-
# type: () -> None
|
|
42
|
+
def setup_once() -> None:
|
|
43
43
|
patch_get_request_handler()
|
|
44
44
|
|
|
45
45
|
|
|
46
|
-
def _set_transaction_name_and_source(
|
|
47
|
-
|
|
46
|
+
def _set_transaction_name_and_source(
|
|
47
|
+
scope: sentry_sdk.Scope, transaction_style: str, request: Any
|
|
48
|
+
) -> None:
|
|
48
49
|
name = ""
|
|
49
50
|
|
|
50
51
|
if transaction_style == "endpoint":
|
|
@@ -71,12 +72,10 @@ def _set_transaction_name_and_source(scope, transaction_style, request):
|
|
|
71
72
|
)
|
|
72
73
|
|
|
73
74
|
|
|
74
|
-
def patch_get_request_handler():
|
|
75
|
-
# type: () -> None
|
|
75
|
+
def patch_get_request_handler() -> None:
|
|
76
76
|
old_get_request_handler = fastapi.routing.get_request_handler
|
|
77
77
|
|
|
78
|
-
def _sentry_get_request_handler(*args, **kwargs):
|
|
79
|
-
# type: (*Any, **Any) -> Any
|
|
78
|
+
def _sentry_get_request_handler(*args: Any, **kwargs: Any) -> Any:
|
|
80
79
|
dependant = kwargs.get("dependant")
|
|
81
80
|
if (
|
|
82
81
|
dependant
|
|
@@ -86,8 +85,7 @@ def patch_get_request_handler():
|
|
|
86
85
|
old_call = dependant.call
|
|
87
86
|
|
|
88
87
|
@wraps(old_call)
|
|
89
|
-
def _sentry_call(*args, **kwargs):
|
|
90
|
-
# type: (*Any, **Any) -> Any
|
|
88
|
+
def _sentry_call(*args: Any, **kwargs: Any) -> Any:
|
|
91
89
|
current_scope = sentry_sdk.get_current_scope()
|
|
92
90
|
if current_scope.root_span is not None:
|
|
93
91
|
current_scope.root_span.update_active_thread()
|
|
@@ -102,8 +100,7 @@ def patch_get_request_handler():
|
|
|
102
100
|
|
|
103
101
|
old_app = old_get_request_handler(*args, **kwargs)
|
|
104
102
|
|
|
105
|
-
async def _sentry_app(*args, **kwargs):
|
|
106
|
-
# type: (*Any, **Any) -> Any
|
|
103
|
+
async def _sentry_app(*args: Any, **kwargs: Any) -> Any:
|
|
107
104
|
integration = sentry_sdk.get_client().get_integration(FastApiIntegration)
|
|
108
105
|
if integration is None:
|
|
109
106
|
return await old_app(*args, **kwargs)
|
|
@@ -117,10 +114,10 @@ def patch_get_request_handler():
|
|
|
117
114
|
extractor = StarletteRequestExtractor(request)
|
|
118
115
|
info = await extractor.extract_request_info()
|
|
119
116
|
|
|
120
|
-
def _make_request_event_processor(
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
117
|
+
def _make_request_event_processor(
|
|
118
|
+
req: Any, integration: Any
|
|
119
|
+
) -> Callable[[Event, Dict[str, Any]], Event]:
|
|
120
|
+
def event_processor(event: Event, hint: Dict[str, Any]) -> Event:
|
|
124
121
|
|
|
125
122
|
# Extract information from request
|
|
126
123
|
request_info = event.get("request", {})
|
sentry_sdk/integrations/flask.py
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
1
2
|
import sentry_sdk
|
|
2
3
|
from sentry_sdk.consts import SOURCE_FOR_STYLE
|
|
3
4
|
from sentry_sdk.integrations import _check_minimum_version, DidNotEnable, Integration
|
|
@@ -57,10 +58,9 @@ class FlaskIntegration(Integration):
|
|
|
57
58
|
|
|
58
59
|
def __init__(
|
|
59
60
|
self,
|
|
60
|
-
transaction_style="endpoint",
|
|
61
|
-
http_methods_to_capture
|
|
62
|
-
):
|
|
63
|
-
# type: (...) -> None
|
|
61
|
+
transaction_style: str = "endpoint",
|
|
62
|
+
http_methods_to_capture: tuple[str, ...] = DEFAULT_HTTP_METHODS_TO_CAPTURE,
|
|
63
|
+
) -> None:
|
|
64
64
|
if transaction_style not in TRANSACTION_STYLE_VALUES:
|
|
65
65
|
raise ValueError(
|
|
66
66
|
"Invalid value for transaction_style: %s (must be in %s)"
|
|
@@ -70,8 +70,7 @@ class FlaskIntegration(Integration):
|
|
|
70
70
|
self.http_methods_to_capture = tuple(map(str.upper, http_methods_to_capture))
|
|
71
71
|
|
|
72
72
|
@staticmethod
|
|
73
|
-
def setup_once():
|
|
74
|
-
# type: () -> None
|
|
73
|
+
def setup_once() -> None:
|
|
75
74
|
try:
|
|
76
75
|
from quart import Quart # type: ignore
|
|
77
76
|
|
|
@@ -93,8 +92,9 @@ class FlaskIntegration(Integration):
|
|
|
93
92
|
|
|
94
93
|
old_app = Flask.__call__
|
|
95
94
|
|
|
96
|
-
def sentry_patched_wsgi_app(
|
|
97
|
-
|
|
95
|
+
def sentry_patched_wsgi_app(
|
|
96
|
+
self: Any, environ: Dict[str, str], start_response: Callable[..., Any]
|
|
97
|
+
) -> _ScopedResponse:
|
|
98
98
|
if sentry_sdk.get_client().get_integration(FlaskIntegration) is None:
|
|
99
99
|
return old_app(self, environ, start_response)
|
|
100
100
|
|
|
@@ -114,8 +114,9 @@ class FlaskIntegration(Integration):
|
|
|
114
114
|
Flask.__call__ = sentry_patched_wsgi_app
|
|
115
115
|
|
|
116
116
|
|
|
117
|
-
def _add_sentry_trace(
|
|
118
|
-
|
|
117
|
+
def _add_sentry_trace(
|
|
118
|
+
sender: Flask, template: Any, context: Dict[str, Any], **extra: Any
|
|
119
|
+
) -> None:
|
|
119
120
|
if "sentry_trace" in context:
|
|
120
121
|
return
|
|
121
122
|
|
|
@@ -125,8 +126,9 @@ def _add_sentry_trace(sender, template, context, **extra):
|
|
|
125
126
|
context["sentry_trace_meta"] = trace_meta
|
|
126
127
|
|
|
127
128
|
|
|
128
|
-
def _set_transaction_name_and_source(
|
|
129
|
-
|
|
129
|
+
def _set_transaction_name_and_source(
|
|
130
|
+
scope: sentry_sdk.Scope, transaction_style: str, request: Request
|
|
131
|
+
) -> None:
|
|
130
132
|
try:
|
|
131
133
|
name_for_style = {
|
|
132
134
|
"url": request.url_rule.rule,
|
|
@@ -140,8 +142,7 @@ def _set_transaction_name_and_source(scope, transaction_style, request):
|
|
|
140
142
|
pass
|
|
141
143
|
|
|
142
144
|
|
|
143
|
-
def _request_started(app, **kwargs):
|
|
144
|
-
# type: (Flask, **Any) -> None
|
|
145
|
+
def _request_started(app: Flask, **kwargs: Any) -> None:
|
|
145
146
|
integration = sentry_sdk.get_client().get_integration(FlaskIntegration)
|
|
146
147
|
if integration is None:
|
|
147
148
|
return
|
|
@@ -160,47 +161,39 @@ def _request_started(app, **kwargs):
|
|
|
160
161
|
|
|
161
162
|
|
|
162
163
|
class FlaskRequestExtractor(RequestExtractor):
|
|
163
|
-
def env(self):
|
|
164
|
-
# type: () -> Dict[str, str]
|
|
164
|
+
def env(self) -> Dict[str, str]:
|
|
165
165
|
return self.request.environ
|
|
166
166
|
|
|
167
|
-
def cookies(self):
|
|
168
|
-
# type: () -> Dict[Any, Any]
|
|
167
|
+
def cookies(self) -> Dict[Any, Any]:
|
|
169
168
|
return {
|
|
170
169
|
k: v[0] if isinstance(v, list) and len(v) == 1 else v
|
|
171
170
|
for k, v in self.request.cookies.items()
|
|
172
171
|
}
|
|
173
172
|
|
|
174
|
-
def raw_data(self):
|
|
175
|
-
# type: () -> bytes
|
|
173
|
+
def raw_data(self) -> bytes:
|
|
176
174
|
return self.request.get_data()
|
|
177
175
|
|
|
178
|
-
def form(self):
|
|
179
|
-
# type: () -> ImmutableMultiDict[str, Any]
|
|
176
|
+
def form(self) -> ImmutableMultiDict[str, Any]:
|
|
180
177
|
return self.request.form
|
|
181
178
|
|
|
182
|
-
def files(self):
|
|
183
|
-
# type: () -> ImmutableMultiDict[str, Any]
|
|
179
|
+
def files(self) -> ImmutableMultiDict[str, Any]:
|
|
184
180
|
return self.request.files
|
|
185
181
|
|
|
186
|
-
def is_json(self):
|
|
187
|
-
# type: () -> bool
|
|
182
|
+
def is_json(self) -> bool:
|
|
188
183
|
return self.request.is_json
|
|
189
184
|
|
|
190
|
-
def json(self):
|
|
191
|
-
# type: () -> Any
|
|
185
|
+
def json(self) -> Any:
|
|
192
186
|
return self.request.get_json(silent=True)
|
|
193
187
|
|
|
194
|
-
def size_of_file(self, file):
|
|
195
|
-
# type: (FileStorage) -> int
|
|
188
|
+
def size_of_file(self, file: FileStorage) -> int:
|
|
196
189
|
return file.content_length
|
|
197
190
|
|
|
198
191
|
|
|
199
|
-
def _make_request_event_processor(
|
|
200
|
-
|
|
192
|
+
def _make_request_event_processor(
|
|
193
|
+
app: Flask, request: Callable[[], Request], integration: FlaskIntegration
|
|
194
|
+
) -> EventProcessor:
|
|
201
195
|
|
|
202
|
-
def inner(event, hint):
|
|
203
|
-
# type: (Event, dict[str, Any]) -> Event
|
|
196
|
+
def inner(event: Event, hint: dict[str, Any]) -> Event:
|
|
204
197
|
|
|
205
198
|
# if the request is gone we are fine not logging the data from
|
|
206
199
|
# it. This might happen if the processor is pushed away to
|
|
@@ -221,8 +214,9 @@ def _make_request_event_processor(app, request, integration):
|
|
|
221
214
|
|
|
222
215
|
|
|
223
216
|
@ensure_integration_enabled(FlaskIntegration)
|
|
224
|
-
def _capture_exception(
|
|
225
|
-
|
|
217
|
+
def _capture_exception(
|
|
218
|
+
sender: Flask, exception: Union[ValueError, BaseException], **kwargs: Any
|
|
219
|
+
) -> None:
|
|
226
220
|
event, hint = event_from_exception(
|
|
227
221
|
exception,
|
|
228
222
|
client_options=sentry_sdk.get_client().options,
|
|
@@ -232,8 +226,7 @@ def _capture_exception(sender, exception, **kwargs):
|
|
|
232
226
|
sentry_sdk.capture_event(event, hint=hint)
|
|
233
227
|
|
|
234
228
|
|
|
235
|
-
def _add_user_to_event(event):
|
|
236
|
-
# type: (Event) -> None
|
|
229
|
+
def _add_user_to_event(event: Event) -> None:
|
|
237
230
|
if flask_login is None:
|
|
238
231
|
return
|
|
239
232
|
|
sentry_sdk/integrations/gcp.py
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
1
2
|
import functools
|
|
2
3
|
import sys
|
|
3
4
|
from copy import deepcopy
|
|
@@ -39,11 +40,11 @@ if TYPE_CHECKING:
|
|
|
39
40
|
F = TypeVar("F", bound=Callable[..., Any])
|
|
40
41
|
|
|
41
42
|
|
|
42
|
-
def _wrap_func(func):
|
|
43
|
-
# type: (F) -> F
|
|
43
|
+
def _wrap_func(func: F) -> F:
|
|
44
44
|
@functools.wraps(func)
|
|
45
|
-
def sentry_func(
|
|
46
|
-
|
|
45
|
+
def sentry_func(
|
|
46
|
+
functionhandler: Any, gcp_event: Any, *args: Any, **kwargs: Any
|
|
47
|
+
) -> Any:
|
|
47
48
|
client = sentry_sdk.get_client()
|
|
48
49
|
|
|
49
50
|
integration = client.get_integration(GcpIntegration)
|
|
@@ -118,13 +119,11 @@ class GcpIntegration(Integration):
|
|
|
118
119
|
identifier = "gcp"
|
|
119
120
|
origin = f"auto.function.{identifier}"
|
|
120
121
|
|
|
121
|
-
def __init__(self, timeout_warning=False):
|
|
122
|
-
# type: (bool) -> None
|
|
122
|
+
def __init__(self, timeout_warning: bool = False) -> None:
|
|
123
123
|
self.timeout_warning = timeout_warning
|
|
124
124
|
|
|
125
125
|
@staticmethod
|
|
126
|
-
def setup_once():
|
|
127
|
-
# type: () -> None
|
|
126
|
+
def setup_once() -> None:
|
|
128
127
|
import __main__ as gcp_functions
|
|
129
128
|
|
|
130
129
|
if not hasattr(gcp_functions, "worker_v1"):
|
|
@@ -140,11 +139,11 @@ class GcpIntegration(Integration):
|
|
|
140
139
|
)
|
|
141
140
|
|
|
142
141
|
|
|
143
|
-
def _make_request_event_processor(
|
|
144
|
-
|
|
142
|
+
def _make_request_event_processor(
|
|
143
|
+
gcp_event: Any, configured_timeout: Any, initial_time: Any
|
|
144
|
+
) -> EventProcessor:
|
|
145
145
|
|
|
146
|
-
def event_processor(event, hint):
|
|
147
|
-
# type: (Event, Hint) -> Optional[Event]
|
|
146
|
+
def event_processor(event: Event, hint: Hint) -> Optional[Event]:
|
|
148
147
|
|
|
149
148
|
final_time = datetime.now(timezone.utc)
|
|
150
149
|
time_diff = final_time - initial_time
|
|
@@ -195,8 +194,7 @@ def _make_request_event_processor(gcp_event, configured_timeout, initial_time):
|
|
|
195
194
|
return event_processor
|
|
196
195
|
|
|
197
196
|
|
|
198
|
-
def _get_google_cloud_logs_url(final_time):
|
|
199
|
-
# type: (datetime) -> str
|
|
197
|
+
def _get_google_cloud_logs_url(final_time: datetime) -> str:
|
|
200
198
|
"""
|
|
201
199
|
Generates a Google Cloud Logs console URL based on the environment variables
|
|
202
200
|
Arguments:
|
|
@@ -238,8 +236,7 @@ EVENT_TO_ATTRIBUTE = {
|
|
|
238
236
|
}
|
|
239
237
|
|
|
240
238
|
|
|
241
|
-
def _prepopulate_attributes(gcp_event):
|
|
242
|
-
# type: (Any) -> dict[str, Any]
|
|
239
|
+
def _prepopulate_attributes(gcp_event: Any) -> dict[str, Any]:
|
|
243
240
|
attributes = {
|
|
244
241
|
"cloud.provider": "gcp",
|
|
245
242
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
1
2
|
import re
|
|
2
3
|
|
|
3
4
|
import sentry_sdk
|
|
@@ -12,23 +13,12 @@ if TYPE_CHECKING:
|
|
|
12
13
|
from sentry_sdk._types import Event
|
|
13
14
|
|
|
14
15
|
|
|
15
|
-
|
|
16
|
-
TYPE_RE = r"[a-zA-Z0-9._:<>,-]+"
|
|
17
|
-
HEXVAL_RE = r"[A-Fa-f0-9]+"
|
|
18
|
-
|
|
16
|
+
FUNCTION_RE = r"[^@]+?)\s+@\s+0x[0-9a-fA-F]+"
|
|
19
17
|
|
|
20
18
|
FRAME_RE = r"""
|
|
21
|
-
^(?P<index>\d+)\.\s
|
|
22
|
-
(?P<package>{MODULE_RE})\(
|
|
23
|
-
(?P<retval>{TYPE_RE}\ )?
|
|
24
|
-
((?P<function>{TYPE_RE})
|
|
25
|
-
(?P<args>\(.*\))?
|
|
26
|
-
)?
|
|
27
|
-
((?P<constoffset>\ const)?\+0x(?P<offset>{HEXVAL_RE}))?
|
|
28
|
-
\)\s
|
|
29
|
-
\[0x(?P<retaddr>{HEXVAL_RE})\]$
|
|
19
|
+
^(?P<index>\d+)\.\s+(?P<function>{FUNCTION_RE}\s+in\s+(?P<package>.+)$
|
|
30
20
|
""".format(
|
|
31
|
-
|
|
21
|
+
FUNCTION_RE=FUNCTION_RE,
|
|
32
22
|
)
|
|
33
23
|
|
|
34
24
|
FRAME_RE = re.compile(FRAME_RE, re.MULTILINE | re.VERBOSE)
|
|
@@ -38,17 +28,14 @@ class GnuBacktraceIntegration(Integration):
|
|
|
38
28
|
identifier = "gnu_backtrace"
|
|
39
29
|
|
|
40
30
|
@staticmethod
|
|
41
|
-
def setup_once():
|
|
42
|
-
# type: () -> None
|
|
31
|
+
def setup_once() -> None:
|
|
43
32
|
@add_global_event_processor
|
|
44
|
-
def process_gnu_backtrace(event, hint):
|
|
45
|
-
# type: (Event, dict[str, Any]) -> Event
|
|
33
|
+
def process_gnu_backtrace(event: Event, hint: dict[str, Any]) -> Event:
|
|
46
34
|
with capture_internal_exceptions():
|
|
47
35
|
return _process_gnu_backtrace(event, hint)
|
|
48
36
|
|
|
49
37
|
|
|
50
|
-
def _process_gnu_backtrace(event, hint):
|
|
51
|
-
# type: (Event, dict[str, Any]) -> Event
|
|
38
|
+
def _process_gnu_backtrace(event: Event, hint: dict[str, Any]) -> Event:
|
|
52
39
|
if sentry_sdk.get_client().get_integration(GnuBacktraceIntegration) is None:
|
|
53
40
|
return event
|
|
54
41
|
|
sentry_sdk/integrations/gql.py
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
1
2
|
import sentry_sdk
|
|
2
3
|
from sentry_sdk.utils import (
|
|
3
4
|
event_from_exception,
|
|
@@ -34,19 +35,17 @@ class GQLIntegration(Integration):
|
|
|
34
35
|
identifier = "gql"
|
|
35
36
|
|
|
36
37
|
@staticmethod
|
|
37
|
-
def setup_once():
|
|
38
|
-
# type: () -> None
|
|
38
|
+
def setup_once() -> None:
|
|
39
39
|
gql_version = parse_version(gql.__version__)
|
|
40
40
|
_check_minimum_version(GQLIntegration, gql_version)
|
|
41
41
|
|
|
42
42
|
_patch_execute()
|
|
43
43
|
|
|
44
44
|
|
|
45
|
-
def _data_from_document(document):
|
|
46
|
-
# type: (DocumentNode) -> EventDataType
|
|
45
|
+
def _data_from_document(document: DocumentNode) -> EventDataType:
|
|
47
46
|
try:
|
|
48
47
|
operation_ast = get_operation_ast(document)
|
|
49
|
-
data = {"query": print_ast(document)}
|
|
48
|
+
data: EventDataType = {"query": print_ast(document)}
|
|
50
49
|
|
|
51
50
|
if operation_ast is not None:
|
|
52
51
|
data["variables"] = operation_ast.variable_definitions
|
|
@@ -58,8 +57,7 @@ def _data_from_document(document):
|
|
|
58
57
|
return dict()
|
|
59
58
|
|
|
60
59
|
|
|
61
|
-
def _transport_method(transport):
|
|
62
|
-
# type: (Union[Transport, AsyncTransport]) -> str
|
|
60
|
+
def _transport_method(transport: Union[Transport, AsyncTransport]) -> str:
|
|
63
61
|
"""
|
|
64
62
|
The RequestsHTTPTransport allows defining the HTTP method; all
|
|
65
63
|
other transports use POST.
|
|
@@ -70,8 +68,9 @@ def _transport_method(transport):
|
|
|
70
68
|
return "POST"
|
|
71
69
|
|
|
72
70
|
|
|
73
|
-
def _request_info_from_transport(
|
|
74
|
-
|
|
71
|
+
def _request_info_from_transport(
|
|
72
|
+
transport: Union[Transport, AsyncTransport, None],
|
|
73
|
+
) -> Dict[str, str]:
|
|
75
74
|
if transport is None:
|
|
76
75
|
return {}
|
|
77
76
|
|
|
@@ -87,13 +86,13 @@ def _request_info_from_transport(transport):
|
|
|
87
86
|
return request_info
|
|
88
87
|
|
|
89
88
|
|
|
90
|
-
def _patch_execute():
|
|
91
|
-
# type: () -> None
|
|
89
|
+
def _patch_execute() -> None:
|
|
92
90
|
real_execute = gql.Client.execute
|
|
93
91
|
|
|
94
92
|
@ensure_integration_enabled(GQLIntegration, real_execute)
|
|
95
|
-
def sentry_patched_execute(
|
|
96
|
-
|
|
93
|
+
def sentry_patched_execute(
|
|
94
|
+
self: gql.Client, document: DocumentNode, *args: Any, **kwargs: Any
|
|
95
|
+
) -> Any:
|
|
97
96
|
scope = sentry_sdk.get_isolation_scope()
|
|
98
97
|
scope.add_event_processor(_make_gql_event_processor(self, document))
|
|
99
98
|
|
|
@@ -112,10 +111,10 @@ def _patch_execute():
|
|
|
112
111
|
gql.Client.execute = sentry_patched_execute
|
|
113
112
|
|
|
114
113
|
|
|
115
|
-
def _make_gql_event_processor(
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
114
|
+
def _make_gql_event_processor(
|
|
115
|
+
client: gql.Client, document: DocumentNode
|
|
116
|
+
) -> EventProcessor:
|
|
117
|
+
def processor(event: Event, hint: dict[str, Any]) -> Event:
|
|
119
118
|
try:
|
|
120
119
|
errors = hint["exc_info"][1].errors
|
|
121
120
|
except (AttributeError, KeyError):
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
1
2
|
from contextlib import contextmanager
|
|
2
3
|
|
|
3
4
|
import sentry_sdk
|
|
@@ -31,22 +32,21 @@ class GrapheneIntegration(Integration):
|
|
|
31
32
|
identifier = "graphene"
|
|
32
33
|
|
|
33
34
|
@staticmethod
|
|
34
|
-
def setup_once():
|
|
35
|
-
# type: () -> None
|
|
35
|
+
def setup_once() -> None:
|
|
36
36
|
version = package_version("graphene")
|
|
37
37
|
_check_minimum_version(GrapheneIntegration, version)
|
|
38
38
|
|
|
39
39
|
_patch_graphql()
|
|
40
40
|
|
|
41
41
|
|
|
42
|
-
def _patch_graphql():
|
|
43
|
-
# type: () -> None
|
|
42
|
+
def _patch_graphql() -> None:
|
|
44
43
|
old_graphql_sync = graphene_schema.graphql_sync
|
|
45
44
|
old_graphql_async = graphene_schema.graphql
|
|
46
45
|
|
|
47
46
|
@ensure_integration_enabled(GrapheneIntegration, old_graphql_sync)
|
|
48
|
-
def _sentry_patched_graphql_sync(
|
|
49
|
-
|
|
47
|
+
def _sentry_patched_graphql_sync(
|
|
48
|
+
schema: GraphQLSchema, source: Union[str, Source], *args: Any, **kwargs: Any
|
|
49
|
+
) -> ExecutionResult:
|
|
50
50
|
scope = sentry_sdk.get_isolation_scope()
|
|
51
51
|
scope.add_event_processor(_event_processor)
|
|
52
52
|
|
|
@@ -68,8 +68,9 @@ def _patch_graphql():
|
|
|
68
68
|
|
|
69
69
|
return result
|
|
70
70
|
|
|
71
|
-
async def _sentry_patched_graphql_async(
|
|
72
|
-
|
|
71
|
+
async def _sentry_patched_graphql_async(
|
|
72
|
+
schema: GraphQLSchema, source: Union[str, Source], *args: Any, **kwargs: Any
|
|
73
|
+
) -> ExecutionResult:
|
|
73
74
|
integration = sentry_sdk.get_client().get_integration(GrapheneIntegration)
|
|
74
75
|
if integration is None:
|
|
75
76
|
return await old_graphql_async(schema, source, *args, **kwargs)
|
|
@@ -99,8 +100,7 @@ def _patch_graphql():
|
|
|
99
100
|
graphene_schema.graphql = _sentry_patched_graphql_async
|
|
100
101
|
|
|
101
102
|
|
|
102
|
-
def _event_processor(event, hint):
|
|
103
|
-
# type: (Event, Dict[str, Any]) -> Event
|
|
103
|
+
def _event_processor(event: Event, hint: Dict[str, Any]) -> Event:
|
|
104
104
|
if should_send_default_pii():
|
|
105
105
|
request_info = event.setdefault("request", {})
|
|
106
106
|
request_info["api_target"] = "graphql"
|
|
@@ -112,8 +112,9 @@ def _event_processor(event, hint):
|
|
|
112
112
|
|
|
113
113
|
|
|
114
114
|
@contextmanager
|
|
115
|
-
def graphql_span(
|
|
116
|
-
|
|
115
|
+
def graphql_span(
|
|
116
|
+
schema: GraphQLSchema, source: Union[str, Source], kwargs: Dict[str, Any]
|
|
117
|
+
) -> Generator[None, None, None]:
|
|
117
118
|
operation_name = kwargs.get("operation_name")
|
|
118
119
|
|
|
119
120
|
operation_type = "query"
|
|
@@ -136,7 +137,7 @@ def graphql_span(schema, source, kwargs):
|
|
|
136
137
|
)
|
|
137
138
|
|
|
138
139
|
with sentry_sdk.start_span(
|
|
139
|
-
op=op, name=operation_name,
|
|
140
|
+
op=op, name=operation_name, only_as_child_span=True
|
|
140
141
|
) as graphql_span:
|
|
141
142
|
graphql_span.set_attribute("graphql.document", source)
|
|
142
143
|
graphql_span.set_attribute("graphql.operation.name", operation_name)
|