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 inspect
|
|
3
4
|
import sys
|
|
@@ -107,18 +108,17 @@ class DjangoIntegration(Integration):
|
|
|
107
108
|
middleware_spans = None
|
|
108
109
|
signals_spans = None
|
|
109
110
|
cache_spans = None
|
|
110
|
-
signals_denylist
|
|
111
|
+
signals_denylist: list[signals.Signal] = []
|
|
111
112
|
|
|
112
113
|
def __init__(
|
|
113
114
|
self,
|
|
114
|
-
transaction_style="url",
|
|
115
|
-
middleware_spans=True,
|
|
116
|
-
signals_spans=True,
|
|
117
|
-
cache_spans=True,
|
|
118
|
-
signals_denylist
|
|
119
|
-
http_methods_to_capture
|
|
120
|
-
):
|
|
121
|
-
# type: (...) -> None
|
|
115
|
+
transaction_style: str = "url",
|
|
116
|
+
middleware_spans: bool = True,
|
|
117
|
+
signals_spans: bool = True,
|
|
118
|
+
cache_spans: bool = True,
|
|
119
|
+
signals_denylist: Optional[list[signals.Signal]] = None,
|
|
120
|
+
http_methods_to_capture: tuple[str, ...] = DEFAULT_HTTP_METHODS_TO_CAPTURE,
|
|
121
|
+
) -> None:
|
|
122
122
|
if transaction_style not in TRANSACTION_STYLE_VALUES:
|
|
123
123
|
raise ValueError(
|
|
124
124
|
"Invalid value for transaction_style: %s (must be in %s)"
|
|
@@ -135,8 +135,7 @@ class DjangoIntegration(Integration):
|
|
|
135
135
|
self.http_methods_to_capture = tuple(map(str.upper, http_methods_to_capture))
|
|
136
136
|
|
|
137
137
|
@staticmethod
|
|
138
|
-
def setup_once():
|
|
139
|
-
# type: () -> None
|
|
138
|
+
def setup_once() -> None:
|
|
140
139
|
_check_minimum_version(DjangoIntegration, DJANGO_VERSION)
|
|
141
140
|
|
|
142
141
|
install_sql_hook()
|
|
@@ -151,8 +150,9 @@ class DjangoIntegration(Integration):
|
|
|
151
150
|
old_app = WSGIHandler.__call__
|
|
152
151
|
|
|
153
152
|
@ensure_integration_enabled(DjangoIntegration, old_app)
|
|
154
|
-
def sentry_patched_wsgi_handler(
|
|
155
|
-
|
|
153
|
+
def sentry_patched_wsgi_handler(
|
|
154
|
+
self: Any, environ: Dict[str, str], start_response: Callable[..., Any]
|
|
155
|
+
) -> _ScopedResponse:
|
|
156
156
|
bound_old_app = old_app.__get__(self, WSGIHandler)
|
|
157
157
|
|
|
158
158
|
from django.conf import settings
|
|
@@ -182,8 +182,9 @@ class DjangoIntegration(Integration):
|
|
|
182
182
|
signals.got_request_exception.connect(_got_request_exception)
|
|
183
183
|
|
|
184
184
|
@add_global_event_processor
|
|
185
|
-
def process_django_templates(
|
|
186
|
-
|
|
185
|
+
def process_django_templates(
|
|
186
|
+
event: Event, hint: Optional[Hint]
|
|
187
|
+
) -> Optional[Event]:
|
|
187
188
|
if hint is None:
|
|
188
189
|
return event
|
|
189
190
|
|
|
@@ -225,8 +226,9 @@ class DjangoIntegration(Integration):
|
|
|
225
226
|
return event
|
|
226
227
|
|
|
227
228
|
@add_global_repr_processor
|
|
228
|
-
def _django_queryset_repr(
|
|
229
|
-
|
|
229
|
+
def _django_queryset_repr(
|
|
230
|
+
value: Any, hint: Dict[str, Any]
|
|
231
|
+
) -> Union[NotImplementedType, str]:
|
|
230
232
|
try:
|
|
231
233
|
# Django 1.6 can fail to import `QuerySet` when Django settings
|
|
232
234
|
# have not yet been initialized.
|
|
@@ -261,8 +263,7 @@ _DRF_PATCHED = False
|
|
|
261
263
|
_DRF_PATCH_LOCK = threading.Lock()
|
|
262
264
|
|
|
263
265
|
|
|
264
|
-
def _patch_drf():
|
|
265
|
-
# type: () -> None
|
|
266
|
+
def _patch_drf() -> None:
|
|
266
267
|
"""
|
|
267
268
|
Patch Django Rest Framework for more/better request data. DRF's request
|
|
268
269
|
type is a wrapper around Django's request type. The attribute we're
|
|
@@ -305,8 +306,9 @@ def _patch_drf():
|
|
|
305
306
|
old_drf_initial = APIView.initial
|
|
306
307
|
|
|
307
308
|
@functools.wraps(old_drf_initial)
|
|
308
|
-
def sentry_patched_drf_initial(
|
|
309
|
-
|
|
309
|
+
def sentry_patched_drf_initial(
|
|
310
|
+
self: APIView, request: Any, *args: Any, **kwargs: Any
|
|
311
|
+
) -> Any:
|
|
310
312
|
with capture_internal_exceptions():
|
|
311
313
|
request._request._sentry_drf_request_backref = weakref.ref(
|
|
312
314
|
request
|
|
@@ -317,8 +319,7 @@ def _patch_drf():
|
|
|
317
319
|
APIView.initial = sentry_patched_drf_initial
|
|
318
320
|
|
|
319
321
|
|
|
320
|
-
def _patch_channels():
|
|
321
|
-
# type: () -> None
|
|
322
|
+
def _patch_channels() -> None:
|
|
322
323
|
try:
|
|
323
324
|
from channels.http import AsgiHandler # type: ignore
|
|
324
325
|
except ImportError:
|
|
@@ -342,8 +343,7 @@ def _patch_channels():
|
|
|
342
343
|
patch_channels_asgi_handler_impl(AsgiHandler)
|
|
343
344
|
|
|
344
345
|
|
|
345
|
-
def _patch_django_asgi_handler():
|
|
346
|
-
# type: () -> None
|
|
346
|
+
def _patch_django_asgi_handler() -> None:
|
|
347
347
|
try:
|
|
348
348
|
from django.core.handlers.asgi import ASGIHandler
|
|
349
349
|
except ImportError:
|
|
@@ -364,8 +364,9 @@ def _patch_django_asgi_handler():
|
|
|
364
364
|
patch_django_asgi_handler_impl(ASGIHandler)
|
|
365
365
|
|
|
366
366
|
|
|
367
|
-
def _set_transaction_name_and_source(
|
|
368
|
-
|
|
367
|
+
def _set_transaction_name_and_source(
|
|
368
|
+
scope: sentry_sdk.Scope, transaction_style: str, request: WSGIRequest
|
|
369
|
+
) -> None:
|
|
369
370
|
try:
|
|
370
371
|
transaction_name = None
|
|
371
372
|
if transaction_style == "function_name":
|
|
@@ -408,8 +409,7 @@ def _set_transaction_name_and_source(scope, transaction_style, request):
|
|
|
408
409
|
pass
|
|
409
410
|
|
|
410
411
|
|
|
411
|
-
def _before_get_response(request):
|
|
412
|
-
# type: (WSGIRequest) -> None
|
|
412
|
+
def _before_get_response(request: WSGIRequest) -> None:
|
|
413
413
|
integration = sentry_sdk.get_client().get_integration(DjangoIntegration)
|
|
414
414
|
if integration is None:
|
|
415
415
|
return
|
|
@@ -425,8 +425,9 @@ def _before_get_response(request):
|
|
|
425
425
|
)
|
|
426
426
|
|
|
427
427
|
|
|
428
|
-
def _attempt_resolve_again(
|
|
429
|
-
|
|
428
|
+
def _attempt_resolve_again(
|
|
429
|
+
request: WSGIRequest, scope: sentry_sdk.Scope, transaction_style: str
|
|
430
|
+
) -> None:
|
|
430
431
|
"""
|
|
431
432
|
Some django middlewares overwrite request.urlconf
|
|
432
433
|
so we need to respect that contract,
|
|
@@ -438,8 +439,7 @@ def _attempt_resolve_again(request, scope, transaction_style):
|
|
|
438
439
|
_set_transaction_name_and_source(scope, transaction_style, request)
|
|
439
440
|
|
|
440
441
|
|
|
441
|
-
def _after_get_response(request):
|
|
442
|
-
# type: (WSGIRequest) -> None
|
|
442
|
+
def _after_get_response(request: WSGIRequest) -> None:
|
|
443
443
|
integration = sentry_sdk.get_client().get_integration(DjangoIntegration)
|
|
444
444
|
if integration is None or integration.transaction_style != "url":
|
|
445
445
|
return
|
|
@@ -448,8 +448,7 @@ def _after_get_response(request):
|
|
|
448
448
|
_attempt_resolve_again(request, scope, integration.transaction_style)
|
|
449
449
|
|
|
450
450
|
|
|
451
|
-
def _patch_get_response():
|
|
452
|
-
# type: () -> None
|
|
451
|
+
def _patch_get_response() -> None:
|
|
453
452
|
"""
|
|
454
453
|
patch get_response, because at that point we have the Django request object
|
|
455
454
|
"""
|
|
@@ -458,8 +457,9 @@ def _patch_get_response():
|
|
|
458
457
|
old_get_response = BaseHandler.get_response
|
|
459
458
|
|
|
460
459
|
@functools.wraps(old_get_response)
|
|
461
|
-
def sentry_patched_get_response(
|
|
462
|
-
|
|
460
|
+
def sentry_patched_get_response(
|
|
461
|
+
self: Any, request: WSGIRequest
|
|
462
|
+
) -> Union[HttpResponse, BaseException]:
|
|
463
463
|
_before_get_response(request)
|
|
464
464
|
rv = old_get_response(self, request)
|
|
465
465
|
_after_get_response(request)
|
|
@@ -473,10 +473,10 @@ def _patch_get_response():
|
|
|
473
473
|
patch_get_response_async(BaseHandler, _before_get_response)
|
|
474
474
|
|
|
475
475
|
|
|
476
|
-
def _make_wsgi_request_event_processor(
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
476
|
+
def _make_wsgi_request_event_processor(
|
|
477
|
+
weak_request: Callable[[], WSGIRequest], integration: DjangoIntegration
|
|
478
|
+
) -> EventProcessor:
|
|
479
|
+
def wsgi_request_event_processor(event: Event, hint: dict[str, Any]) -> Event:
|
|
480
480
|
# if the request is gone we are fine not logging the data from
|
|
481
481
|
# it. This might happen if the processor is pushed away to
|
|
482
482
|
# another thread.
|
|
@@ -501,8 +501,7 @@ def _make_wsgi_request_event_processor(weak_request, integration):
|
|
|
501
501
|
return wsgi_request_event_processor
|
|
502
502
|
|
|
503
503
|
|
|
504
|
-
def _got_request_exception(request=None, **kwargs):
|
|
505
|
-
# type: (WSGIRequest, **Any) -> None
|
|
504
|
+
def _got_request_exception(request: WSGIRequest = None, **kwargs: Any) -> None:
|
|
506
505
|
client = sentry_sdk.get_client()
|
|
507
506
|
integration = client.get_integration(DjangoIntegration)
|
|
508
507
|
if integration is None:
|
|
@@ -521,8 +520,7 @@ def _got_request_exception(request=None, **kwargs):
|
|
|
521
520
|
|
|
522
521
|
|
|
523
522
|
class DjangoRequestExtractor(RequestExtractor):
|
|
524
|
-
def __init__(self, request):
|
|
525
|
-
# type: (Union[WSGIRequest, ASGIRequest]) -> None
|
|
523
|
+
def __init__(self, request: Union[WSGIRequest, ASGIRequest]) -> None:
|
|
526
524
|
try:
|
|
527
525
|
drf_request = request._sentry_drf_request_backref()
|
|
528
526
|
if drf_request is not None:
|
|
@@ -531,18 +529,16 @@ class DjangoRequestExtractor(RequestExtractor):
|
|
|
531
529
|
pass
|
|
532
530
|
self.request = request
|
|
533
531
|
|
|
534
|
-
def env(self):
|
|
535
|
-
# type: () -> Dict[str, str]
|
|
532
|
+
def env(self) -> Dict[str, str]:
|
|
536
533
|
return self.request.META
|
|
537
534
|
|
|
538
|
-
def cookies(self):
|
|
539
|
-
# type: () -> Dict[str, Union[str, AnnotatedValue]]
|
|
535
|
+
def cookies(self) -> Dict[str, Union[str, AnnotatedValue]]:
|
|
540
536
|
privacy_cookies = [
|
|
541
537
|
django_settings.CSRF_COOKIE_NAME,
|
|
542
538
|
django_settings.SESSION_COOKIE_NAME,
|
|
543
539
|
]
|
|
544
540
|
|
|
545
|
-
clean_cookies
|
|
541
|
+
clean_cookies: Dict[str, Union[str, AnnotatedValue]] = {}
|
|
546
542
|
for key, val in self.request.COOKIES.items():
|
|
547
543
|
if key in privacy_cookies:
|
|
548
544
|
clean_cookies[key] = SENSITIVE_DATA_SUBSTITUTE
|
|
@@ -551,32 +547,26 @@ class DjangoRequestExtractor(RequestExtractor):
|
|
|
551
547
|
|
|
552
548
|
return clean_cookies
|
|
553
549
|
|
|
554
|
-
def raw_data(self):
|
|
555
|
-
# type: () -> bytes
|
|
550
|
+
def raw_data(self) -> bytes:
|
|
556
551
|
return self.request.body
|
|
557
552
|
|
|
558
|
-
def form(self):
|
|
559
|
-
# type: () -> QueryDict
|
|
553
|
+
def form(self) -> QueryDict:
|
|
560
554
|
return self.request.POST
|
|
561
555
|
|
|
562
|
-
def files(self):
|
|
563
|
-
# type: () -> MultiValueDict
|
|
556
|
+
def files(self) -> MultiValueDict:
|
|
564
557
|
return self.request.FILES
|
|
565
558
|
|
|
566
|
-
def size_of_file(self, file):
|
|
567
|
-
# type: (Any) -> int
|
|
559
|
+
def size_of_file(self, file: Any) -> int:
|
|
568
560
|
return file.size
|
|
569
561
|
|
|
570
|
-
def parsed_body(self):
|
|
571
|
-
# type: () -> Optional[Dict[str, Any]]
|
|
562
|
+
def parsed_body(self) -> Optional[Dict[str, Any]]:
|
|
572
563
|
try:
|
|
573
564
|
return self.request.data
|
|
574
565
|
except Exception:
|
|
575
566
|
return RequestExtractor.parsed_body(self)
|
|
576
567
|
|
|
577
568
|
|
|
578
|
-
def _set_user_info(request, event):
|
|
579
|
-
# type: (WSGIRequest, Event) -> None
|
|
569
|
+
def _set_user_info(request: WSGIRequest, event: Event) -> None:
|
|
580
570
|
user_info = event.setdefault("user", {})
|
|
581
571
|
|
|
582
572
|
user = getattr(request, "user", None)
|
|
@@ -600,8 +590,7 @@ def _set_user_info(request, event):
|
|
|
600
590
|
pass
|
|
601
591
|
|
|
602
592
|
|
|
603
|
-
def install_sql_hook():
|
|
604
|
-
# type: () -> None
|
|
593
|
+
def install_sql_hook() -> None:
|
|
605
594
|
"""If installed this causes Django's queries to be captured."""
|
|
606
595
|
try:
|
|
607
596
|
from django.db.backends.utils import CursorWrapper
|
|
@@ -615,8 +604,7 @@ def install_sql_hook():
|
|
|
615
604
|
real_connect = BaseDatabaseWrapper.connect
|
|
616
605
|
|
|
617
606
|
@ensure_integration_enabled(DjangoIntegration, real_execute)
|
|
618
|
-
def execute(self, sql, params=None):
|
|
619
|
-
# type: (CursorWrapper, Any, Optional[Any]) -> Any
|
|
607
|
+
def execute(self: CursorWrapper, sql: Any, params: Optional[Any] = None) -> Any:
|
|
620
608
|
with record_sql_queries(
|
|
621
609
|
cursor=self.cursor,
|
|
622
610
|
query=sql,
|
|
@@ -634,8 +622,7 @@ def install_sql_hook():
|
|
|
634
622
|
return result
|
|
635
623
|
|
|
636
624
|
@ensure_integration_enabled(DjangoIntegration, real_executemany)
|
|
637
|
-
def executemany(self, sql, param_list):
|
|
638
|
-
# type: (CursorWrapper, Any, List[Any]) -> Any
|
|
625
|
+
def executemany(self: CursorWrapper, sql: Any, param_list: List[Any]) -> Any:
|
|
639
626
|
with record_sql_queries(
|
|
640
627
|
cursor=self.cursor,
|
|
641
628
|
query=sql,
|
|
@@ -654,8 +641,7 @@ def install_sql_hook():
|
|
|
654
641
|
return result
|
|
655
642
|
|
|
656
643
|
@ensure_integration_enabled(DjangoIntegration, real_connect)
|
|
657
|
-
def connect(self):
|
|
658
|
-
# type: (BaseDatabaseWrapper) -> None
|
|
644
|
+
def connect(self: BaseDatabaseWrapper) -> None:
|
|
659
645
|
with capture_internal_exceptions():
|
|
660
646
|
sentry_sdk.add_breadcrumb(message="connect", category="query")
|
|
661
647
|
|
|
@@ -674,8 +660,7 @@ def install_sql_hook():
|
|
|
674
660
|
ignore_logger("django.db.backends")
|
|
675
661
|
|
|
676
662
|
|
|
677
|
-
def _set_db_data(span, cursor_or_db):
|
|
678
|
-
# type: (Span, Any) -> None
|
|
663
|
+
def _set_db_data(span: Span, cursor_or_db: Any) -> None:
|
|
679
664
|
db = cursor_or_db.db if hasattr(cursor_or_db, "db") else cursor_or_db
|
|
680
665
|
vendor = db.vendor
|
|
681
666
|
span.set_attribute(SPANDATA.DB_SYSTEM, vendor)
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
1
3
|
"""
|
|
2
4
|
Instrumentation for Django 3.0
|
|
3
5
|
|
|
@@ -51,10 +53,8 @@ else:
|
|
|
51
53
|
return func
|
|
52
54
|
|
|
53
55
|
|
|
54
|
-
def _make_asgi_request_event_processor(request):
|
|
55
|
-
|
|
56
|
-
def asgi_request_event_processor(event, hint):
|
|
57
|
-
# type: (Event, dict[str, Any]) -> Event
|
|
56
|
+
def _make_asgi_request_event_processor(request: ASGIRequest) -> EventProcessor:
|
|
57
|
+
def asgi_request_event_processor(event: Event, hint: dict[str, Any]) -> Event:
|
|
58
58
|
# if the request is gone we are fine not logging the data from
|
|
59
59
|
# it. This might happen if the processor is pushed away to
|
|
60
60
|
# another thread.
|
|
@@ -81,16 +81,16 @@ def _make_asgi_request_event_processor(request):
|
|
|
81
81
|
return asgi_request_event_processor
|
|
82
82
|
|
|
83
83
|
|
|
84
|
-
def patch_django_asgi_handler_impl(cls):
|
|
85
|
-
# type: (Any) -> None
|
|
84
|
+
def patch_django_asgi_handler_impl(cls: Any) -> None:
|
|
86
85
|
|
|
87
86
|
from sentry_sdk.integrations.django import DjangoIntegration
|
|
88
87
|
|
|
89
88
|
old_app = cls.__call__
|
|
90
89
|
|
|
91
90
|
@functools.wraps(old_app)
|
|
92
|
-
async def sentry_patched_asgi_handler(
|
|
93
|
-
|
|
91
|
+
async def sentry_patched_asgi_handler(
|
|
92
|
+
self: Any, scope: Any, receive: Any, send: Any
|
|
93
|
+
) -> Any:
|
|
94
94
|
integration = sentry_sdk.get_client().get_integration(DjangoIntegration)
|
|
95
95
|
if integration is None:
|
|
96
96
|
return await old_app(self, scope, receive, send)
|
|
@@ -111,8 +111,7 @@ def patch_django_asgi_handler_impl(cls):
|
|
|
111
111
|
old_create_request = cls.create_request
|
|
112
112
|
|
|
113
113
|
@ensure_integration_enabled(DjangoIntegration, old_create_request)
|
|
114
|
-
def sentry_patched_create_request(self, *args, **kwargs):
|
|
115
|
-
# type: (Any, *Any, **Any) -> Any
|
|
114
|
+
def sentry_patched_create_request(self: Any, *args: Any, **kwargs: Any) -> Any:
|
|
116
115
|
request, error_response = old_create_request(self, *args, **kwargs)
|
|
117
116
|
scope = sentry_sdk.get_isolation_scope()
|
|
118
117
|
scope.add_event_processor(_make_asgi_request_event_processor(request))
|
|
@@ -122,21 +121,20 @@ def patch_django_asgi_handler_impl(cls):
|
|
|
122
121
|
cls.create_request = sentry_patched_create_request
|
|
123
122
|
|
|
124
123
|
|
|
125
|
-
def patch_get_response_async(cls, _before_get_response):
|
|
126
|
-
# type: (Any, Any) -> None
|
|
124
|
+
def patch_get_response_async(cls: Any, _before_get_response: Any) -> None:
|
|
127
125
|
old_get_response_async = cls.get_response_async
|
|
128
126
|
|
|
129
127
|
@functools.wraps(old_get_response_async)
|
|
130
|
-
async def sentry_patched_get_response_async(
|
|
131
|
-
|
|
128
|
+
async def sentry_patched_get_response_async(
|
|
129
|
+
self: Any, request: Any
|
|
130
|
+
) -> Union[HttpResponse, BaseException]:
|
|
132
131
|
_before_get_response(request)
|
|
133
132
|
return await old_get_response_async(self, request)
|
|
134
133
|
|
|
135
134
|
cls.get_response_async = sentry_patched_get_response_async
|
|
136
135
|
|
|
137
136
|
|
|
138
|
-
def patch_channels_asgi_handler_impl(cls):
|
|
139
|
-
# type: (Any) -> None
|
|
137
|
+
def patch_channels_asgi_handler_impl(cls: Any) -> None:
|
|
140
138
|
import channels # type: ignore
|
|
141
139
|
|
|
142
140
|
from sentry_sdk.integrations.django import DjangoIntegration
|
|
@@ -145,8 +143,9 @@ def patch_channels_asgi_handler_impl(cls):
|
|
|
145
143
|
old_app = cls.__call__
|
|
146
144
|
|
|
147
145
|
@functools.wraps(old_app)
|
|
148
|
-
async def sentry_patched_asgi_handler(
|
|
149
|
-
|
|
146
|
+
async def sentry_patched_asgi_handler(
|
|
147
|
+
self: Any, receive: Any, send: Any
|
|
148
|
+
) -> Any:
|
|
150
149
|
integration = sentry_sdk.get_client().get_integration(DjangoIntegration)
|
|
151
150
|
if integration is None:
|
|
152
151
|
return await old_app(self, receive, send)
|
|
@@ -168,13 +167,11 @@ def patch_channels_asgi_handler_impl(cls):
|
|
|
168
167
|
patch_django_asgi_handler_impl(cls)
|
|
169
168
|
|
|
170
169
|
|
|
171
|
-
def wrap_async_view(callback):
|
|
172
|
-
# type: (Any) -> Any
|
|
170
|
+
def wrap_async_view(callback: Any) -> Any:
|
|
173
171
|
from sentry_sdk.integrations.django import DjangoIntegration
|
|
174
172
|
|
|
175
173
|
@functools.wraps(callback)
|
|
176
|
-
async def sentry_wrapped_callback(request, *args, **kwargs):
|
|
177
|
-
# type: (Any, *Any, **Any) -> Any
|
|
174
|
+
async def sentry_wrapped_callback(request: Any, *args: Any, **kwargs: Any) -> Any:
|
|
178
175
|
current_scope = sentry_sdk.get_current_scope()
|
|
179
176
|
if current_scope.root_span is not None:
|
|
180
177
|
current_scope.root_span.update_active_thread()
|
|
@@ -194,8 +191,7 @@ def wrap_async_view(callback):
|
|
|
194
191
|
return sentry_wrapped_callback
|
|
195
192
|
|
|
196
193
|
|
|
197
|
-
def _asgi_middleware_mixin_factory(_check_middleware_span):
|
|
198
|
-
# type: (Callable[..., Any]) -> Any
|
|
194
|
+
def _asgi_middleware_mixin_factory(_check_middleware_span: Callable[..., Any]) -> Any:
|
|
199
195
|
"""
|
|
200
196
|
Mixin class factory that generates a middleware mixin for handling requests
|
|
201
197
|
in async mode.
|
|
@@ -205,14 +201,12 @@ def _asgi_middleware_mixin_factory(_check_middleware_span):
|
|
|
205
201
|
if TYPE_CHECKING:
|
|
206
202
|
_inner = None
|
|
207
203
|
|
|
208
|
-
def __init__(self, get_response):
|
|
209
|
-
# type: (Callable[..., Any]) -> None
|
|
204
|
+
def __init__(self, get_response: Callable[..., Any]) -> None:
|
|
210
205
|
self.get_response = get_response
|
|
211
206
|
self._acall_method = None
|
|
212
207
|
self._async_check()
|
|
213
208
|
|
|
214
|
-
def _async_check(self):
|
|
215
|
-
# type: () -> None
|
|
209
|
+
def _async_check(self) -> None:
|
|
216
210
|
"""
|
|
217
211
|
If get_response is a coroutine function, turns us into async mode so
|
|
218
212
|
a thread is not consumed during a whole request.
|
|
@@ -221,16 +215,14 @@ def _asgi_middleware_mixin_factory(_check_middleware_span):
|
|
|
221
215
|
if iscoroutinefunction(self.get_response):
|
|
222
216
|
markcoroutinefunction(self)
|
|
223
217
|
|
|
224
|
-
def async_route_check(self):
|
|
225
|
-
# type: () -> bool
|
|
218
|
+
def async_route_check(self) -> bool:
|
|
226
219
|
"""
|
|
227
220
|
Function that checks if we are in async mode,
|
|
228
221
|
and if we are forwards the handling of requests to __acall__
|
|
229
222
|
"""
|
|
230
223
|
return iscoroutinefunction(self.get_response)
|
|
231
224
|
|
|
232
|
-
async def __acall__(self, *args, **kwargs):
|
|
233
|
-
# type: (*Any, **Any) -> Any
|
|
225
|
+
async def __acall__(self, *args: Any, **kwargs: Any) -> Any:
|
|
234
226
|
f = self._acall_method
|
|
235
227
|
if f is None:
|
|
236
228
|
if hasattr(self._inner, "__acall__"):
|
|
@@ -241,9 +233,9 @@ def _asgi_middleware_mixin_factory(_check_middleware_span):
|
|
|
241
233
|
middleware_span = _check_middleware_span(old_method=f)
|
|
242
234
|
|
|
243
235
|
if middleware_span is None:
|
|
244
|
-
return await f(*args, **kwargs)
|
|
236
|
+
return await f(*args, **kwargs) # type: ignore
|
|
245
237
|
|
|
246
238
|
with middleware_span:
|
|
247
|
-
return await f(*args, **kwargs)
|
|
239
|
+
return await f(*args, **kwargs) # type: ignore
|
|
248
240
|
|
|
249
241
|
return SentryASGIMixin
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
1
2
|
import functools
|
|
2
3
|
from typing import TYPE_CHECKING
|
|
3
4
|
from sentry_sdk.integrations.redis.utils import _get_safe_key, _key_as_string
|
|
@@ -28,22 +29,29 @@ METHODS_TO_INSTRUMENT = [
|
|
|
28
29
|
]
|
|
29
30
|
|
|
30
31
|
|
|
31
|
-
def _get_span_description(
|
|
32
|
-
|
|
32
|
+
def _get_span_description(
|
|
33
|
+
method_name: str, args: tuple[Any], kwargs: dict[str, Any]
|
|
34
|
+
) -> str:
|
|
33
35
|
return _key_as_string(_get_safe_key(method_name, args, kwargs))
|
|
34
36
|
|
|
35
37
|
|
|
36
|
-
def _patch_cache_method(
|
|
37
|
-
|
|
38
|
+
def _patch_cache_method(
|
|
39
|
+
cache: CacheHandler, method_name: str, address: Optional[str], port: Optional[int]
|
|
40
|
+
) -> None:
|
|
38
41
|
from sentry_sdk.integrations.django import DjangoIntegration
|
|
39
42
|
|
|
40
43
|
original_method = getattr(cache, method_name)
|
|
41
44
|
|
|
42
45
|
@ensure_integration_enabled(DjangoIntegration, original_method)
|
|
43
46
|
def _instrument_call(
|
|
44
|
-
cache
|
|
45
|
-
|
|
46
|
-
|
|
47
|
+
cache: CacheHandler,
|
|
48
|
+
method_name: str,
|
|
49
|
+
original_method: Callable[..., Any],
|
|
50
|
+
args: tuple[Any, ...],
|
|
51
|
+
kwargs: dict[str, Any],
|
|
52
|
+
address: Optional[str],
|
|
53
|
+
port: Optional[int],
|
|
54
|
+
) -> Any:
|
|
47
55
|
is_set_operation = method_name.startswith("set")
|
|
48
56
|
is_get_operation = not is_set_operation
|
|
49
57
|
|
|
@@ -91,8 +99,7 @@ def _patch_cache_method(cache, method_name, address, port):
|
|
|
91
99
|
return value
|
|
92
100
|
|
|
93
101
|
@functools.wraps(original_method)
|
|
94
|
-
def sentry_method(*args, **kwargs):
|
|
95
|
-
# type: (*Any, **Any) -> Any
|
|
102
|
+
def sentry_method(*args: Any, **kwargs: Any) -> Any:
|
|
96
103
|
return _instrument_call(
|
|
97
104
|
cache, method_name, original_method, args, kwargs, address, port
|
|
98
105
|
)
|
|
@@ -100,16 +107,16 @@ def _patch_cache_method(cache, method_name, address, port):
|
|
|
100
107
|
setattr(cache, method_name, sentry_method)
|
|
101
108
|
|
|
102
109
|
|
|
103
|
-
def _patch_cache(
|
|
104
|
-
|
|
110
|
+
def _patch_cache(
|
|
111
|
+
cache: CacheHandler, address: Optional[str] = None, port: Optional[int] = None
|
|
112
|
+
) -> None:
|
|
105
113
|
if not hasattr(cache, "_sentry_patched"):
|
|
106
114
|
for method_name in METHODS_TO_INSTRUMENT:
|
|
107
115
|
_patch_cache_method(cache, method_name, address, port)
|
|
108
116
|
cache._sentry_patched = True
|
|
109
117
|
|
|
110
118
|
|
|
111
|
-
def _get_address_port(settings):
|
|
112
|
-
# type: (dict[str, Any]) -> tuple[Optional[str], Optional[int]]
|
|
119
|
+
def _get_address_port(settings: dict[str, Any]) -> tuple[Optional[str], Optional[int]]:
|
|
113
120
|
location = settings.get("LOCATION")
|
|
114
121
|
|
|
115
122
|
# TODO: location can also be an array of locations
|
|
@@ -134,8 +141,7 @@ def _get_address_port(settings):
|
|
|
134
141
|
return address, int(port) if port is not None else None
|
|
135
142
|
|
|
136
143
|
|
|
137
|
-
def patch_caching():
|
|
138
|
-
# type: () -> None
|
|
144
|
+
def patch_caching() -> None:
|
|
139
145
|
from sentry_sdk.integrations.django import DjangoIntegration
|
|
140
146
|
|
|
141
147
|
if not hasattr(CacheHandler, "_sentry_patched"):
|
|
@@ -143,8 +149,7 @@ def patch_caching():
|
|
|
143
149
|
original_get_item = CacheHandler.__getitem__
|
|
144
150
|
|
|
145
151
|
@functools.wraps(original_get_item)
|
|
146
|
-
def sentry_get_item(self, alias):
|
|
147
|
-
# type: (CacheHandler, str) -> Any
|
|
152
|
+
def sentry_get_item(self: CacheHandler, alias: str) -> Any:
|
|
148
153
|
cache = original_get_item(self, alias)
|
|
149
154
|
|
|
150
155
|
integration = sentry_sdk.get_client().get_integration(DjangoIntegration)
|
|
@@ -166,8 +171,7 @@ def patch_caching():
|
|
|
166
171
|
original_create_connection = CacheHandler.create_connection
|
|
167
172
|
|
|
168
173
|
@functools.wraps(original_create_connection)
|
|
169
|
-
def sentry_create_connection(self, alias):
|
|
170
|
-
# type: (CacheHandler, str) -> Any
|
|
174
|
+
def sentry_create_connection(self: CacheHandler, alias: str) -> Any:
|
|
171
175
|
cache = original_create_connection(self, alias)
|
|
172
176
|
|
|
173
177
|
integration = sentry_sdk.get_client().get_integration(DjangoIntegration)
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
1
3
|
"""
|
|
2
4
|
Create spans from Django middleware invocations
|
|
3
5
|
"""
|
|
@@ -38,14 +40,12 @@ else:
|
|
|
38
40
|
from .asgi import _asgi_middleware_mixin_factory
|
|
39
41
|
|
|
40
42
|
|
|
41
|
-
def patch_django_middlewares():
|
|
42
|
-
# type: () -> None
|
|
43
|
+
def patch_django_middlewares() -> None:
|
|
43
44
|
from django.core.handlers import base
|
|
44
45
|
|
|
45
46
|
old_import_string = base.import_string
|
|
46
47
|
|
|
47
|
-
def sentry_patched_import_string(dotted_path):
|
|
48
|
-
# type: (str) -> Any
|
|
48
|
+
def sentry_patched_import_string(dotted_path: str) -> Any:
|
|
49
49
|
rv = old_import_string(dotted_path)
|
|
50
50
|
|
|
51
51
|
if _import_string_should_wrap_middleware.get(None):
|
|
@@ -57,8 +57,7 @@ def patch_django_middlewares():
|
|
|
57
57
|
|
|
58
58
|
old_load_middleware = base.BaseHandler.load_middleware
|
|
59
59
|
|
|
60
|
-
def sentry_patched_load_middleware(*args, **kwargs):
|
|
61
|
-
# type: (Any, Any) -> Any
|
|
60
|
+
def sentry_patched_load_middleware(*args: Any, **kwargs: Any) -> Any:
|
|
62
61
|
_import_string_should_wrap_middleware.set(True)
|
|
63
62
|
try:
|
|
64
63
|
return old_load_middleware(*args, **kwargs)
|
|
@@ -68,12 +67,10 @@ def patch_django_middlewares():
|
|
|
68
67
|
base.BaseHandler.load_middleware = sentry_patched_load_middleware
|
|
69
68
|
|
|
70
69
|
|
|
71
|
-
def _wrap_middleware(middleware, middleware_name):
|
|
72
|
-
# type: (Any, str) -> Any
|
|
70
|
+
def _wrap_middleware(middleware: Any, middleware_name: str) -> Any:
|
|
73
71
|
from sentry_sdk.integrations.django import DjangoIntegration
|
|
74
72
|
|
|
75
|
-
def _check_middleware_span(old_method):
|
|
76
|
-
# type: (Callable[..., Any]) -> Optional[Span]
|
|
73
|
+
def _check_middleware_span(old_method: Callable[..., Any]) -> Optional[Span]:
|
|
77
74
|
integration = sentry_sdk.get_client().get_integration(DjangoIntegration)
|
|
78
75
|
if integration is None or not integration.middleware_spans:
|
|
79
76
|
return None
|
|
@@ -96,12 +93,10 @@ def _wrap_middleware(middleware, middleware_name):
|
|
|
96
93
|
|
|
97
94
|
return middleware_span
|
|
98
95
|
|
|
99
|
-
def _get_wrapped_method(old_method):
|
|
100
|
-
# type: (F) -> F
|
|
96
|
+
def _get_wrapped_method(old_method: F) -> F:
|
|
101
97
|
with capture_internal_exceptions():
|
|
102
98
|
|
|
103
|
-
def sentry_wrapped_method(*args, **kwargs):
|
|
104
|
-
# type: (*Any, **Any) -> Any
|
|
99
|
+
def sentry_wrapped_method(*args: Any, **kwargs: Any) -> Any:
|
|
105
100
|
middleware_span = _check_middleware_span(old_method)
|
|
106
101
|
|
|
107
102
|
if middleware_span is None:
|
|
@@ -131,8 +126,12 @@ def _wrap_middleware(middleware, middleware_name):
|
|
|
131
126
|
middleware, "async_capable", False
|
|
132
127
|
)
|
|
133
128
|
|
|
134
|
-
def __init__(
|
|
135
|
-
|
|
129
|
+
def __init__(
|
|
130
|
+
self,
|
|
131
|
+
get_response: Optional[Callable[..., Any]] = None,
|
|
132
|
+
*args: Any,
|
|
133
|
+
**kwargs: Any,
|
|
134
|
+
) -> None:
|
|
136
135
|
if get_response:
|
|
137
136
|
self._inner = middleware(get_response, *args, **kwargs)
|
|
138
137
|
else:
|
|
@@ -144,8 +143,7 @@ def _wrap_middleware(middleware, middleware_name):
|
|
|
144
143
|
|
|
145
144
|
# We need correct behavior for `hasattr()`, which we can only determine
|
|
146
145
|
# when we have an instance of the middleware we're wrapping.
|
|
147
|
-
def __getattr__(self, method_name):
|
|
148
|
-
# type: (str) -> Any
|
|
146
|
+
def __getattr__(self, method_name: str) -> Any:
|
|
149
147
|
if method_name not in (
|
|
150
148
|
"process_request",
|
|
151
149
|
"process_view",
|
|
@@ -160,8 +158,7 @@ def _wrap_middleware(middleware, middleware_name):
|
|
|
160
158
|
self.__dict__[method_name] = rv
|
|
161
159
|
return rv
|
|
162
160
|
|
|
163
|
-
def __call__(self, *args, **kwargs):
|
|
164
|
-
# type: (*Any, **Any) -> Any
|
|
161
|
+
def __call__(self, *args: Any, **kwargs: Any) -> Any:
|
|
165
162
|
if hasattr(self, "async_route_check") and self.async_route_check():
|
|
166
163
|
return self.__acall__(*args, **kwargs)
|
|
167
164
|
|