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 functools
|
|
2
3
|
import inspect
|
|
3
4
|
import sys
|
|
@@ -8,7 +9,7 @@ from importlib import import_module
|
|
|
8
9
|
import sentry_sdk
|
|
9
10
|
from sentry_sdk.consts import OP, SPANDATA, SOURCE_FOR_STYLE, TransactionSource
|
|
10
11
|
from sentry_sdk.scope import add_global_event_processor, should_send_default_pii
|
|
11
|
-
from sentry_sdk.serializer import add_global_repr_processor
|
|
12
|
+
from sentry_sdk.serializer import add_global_repr_processor, add_repr_sequence_type
|
|
12
13
|
from sentry_sdk.tracing_utils import add_query_source, record_sql_queries
|
|
13
14
|
from sentry_sdk.utils import (
|
|
14
15
|
AnnotatedValue,
|
|
@@ -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.
|
|
@@ -252,6 +254,7 @@ class DjangoIntegration(Integration):
|
|
|
252
254
|
patch_views()
|
|
253
255
|
patch_templates()
|
|
254
256
|
patch_signals()
|
|
257
|
+
add_template_context_repr_sequence()
|
|
255
258
|
|
|
256
259
|
if patch_caching is not None:
|
|
257
260
|
patch_caching()
|
|
@@ -261,8 +264,7 @@ _DRF_PATCHED = False
|
|
|
261
264
|
_DRF_PATCH_LOCK = threading.Lock()
|
|
262
265
|
|
|
263
266
|
|
|
264
|
-
def _patch_drf():
|
|
265
|
-
# type: () -> None
|
|
267
|
+
def _patch_drf() -> None:
|
|
266
268
|
"""
|
|
267
269
|
Patch Django Rest Framework for more/better request data. DRF's request
|
|
268
270
|
type is a wrapper around Django's request type. The attribute we're
|
|
@@ -305,8 +307,9 @@ def _patch_drf():
|
|
|
305
307
|
old_drf_initial = APIView.initial
|
|
306
308
|
|
|
307
309
|
@functools.wraps(old_drf_initial)
|
|
308
|
-
def sentry_patched_drf_initial(
|
|
309
|
-
|
|
310
|
+
def sentry_patched_drf_initial(
|
|
311
|
+
self: APIView, request: Any, *args: Any, **kwargs: Any
|
|
312
|
+
) -> Any:
|
|
310
313
|
with capture_internal_exceptions():
|
|
311
314
|
request._request._sentry_drf_request_backref = weakref.ref(
|
|
312
315
|
request
|
|
@@ -317,8 +320,7 @@ def _patch_drf():
|
|
|
317
320
|
APIView.initial = sentry_patched_drf_initial
|
|
318
321
|
|
|
319
322
|
|
|
320
|
-
def _patch_channels():
|
|
321
|
-
# type: () -> None
|
|
323
|
+
def _patch_channels() -> None:
|
|
322
324
|
try:
|
|
323
325
|
from channels.http import AsgiHandler # type: ignore
|
|
324
326
|
except ImportError:
|
|
@@ -342,8 +344,7 @@ def _patch_channels():
|
|
|
342
344
|
patch_channels_asgi_handler_impl(AsgiHandler)
|
|
343
345
|
|
|
344
346
|
|
|
345
|
-
def _patch_django_asgi_handler():
|
|
346
|
-
# type: () -> None
|
|
347
|
+
def _patch_django_asgi_handler() -> None:
|
|
347
348
|
try:
|
|
348
349
|
from django.core.handlers.asgi import ASGIHandler
|
|
349
350
|
except ImportError:
|
|
@@ -364,8 +365,9 @@ def _patch_django_asgi_handler():
|
|
|
364
365
|
patch_django_asgi_handler_impl(ASGIHandler)
|
|
365
366
|
|
|
366
367
|
|
|
367
|
-
def _set_transaction_name_and_source(
|
|
368
|
-
|
|
368
|
+
def _set_transaction_name_and_source(
|
|
369
|
+
scope: sentry_sdk.Scope, transaction_style: str, request: WSGIRequest
|
|
370
|
+
) -> None:
|
|
369
371
|
try:
|
|
370
372
|
transaction_name = None
|
|
371
373
|
if transaction_style == "function_name":
|
|
@@ -408,8 +410,7 @@ def _set_transaction_name_and_source(scope, transaction_style, request):
|
|
|
408
410
|
pass
|
|
409
411
|
|
|
410
412
|
|
|
411
|
-
def _before_get_response(request):
|
|
412
|
-
# type: (WSGIRequest) -> None
|
|
413
|
+
def _before_get_response(request: WSGIRequest) -> None:
|
|
413
414
|
integration = sentry_sdk.get_client().get_integration(DjangoIntegration)
|
|
414
415
|
if integration is None:
|
|
415
416
|
return
|
|
@@ -425,8 +426,9 @@ def _before_get_response(request):
|
|
|
425
426
|
)
|
|
426
427
|
|
|
427
428
|
|
|
428
|
-
def _attempt_resolve_again(
|
|
429
|
-
|
|
429
|
+
def _attempt_resolve_again(
|
|
430
|
+
request: WSGIRequest, scope: sentry_sdk.Scope, transaction_style: str
|
|
431
|
+
) -> None:
|
|
430
432
|
"""
|
|
431
433
|
Some django middlewares overwrite request.urlconf
|
|
432
434
|
so we need to respect that contract,
|
|
@@ -438,8 +440,7 @@ def _attempt_resolve_again(request, scope, transaction_style):
|
|
|
438
440
|
_set_transaction_name_and_source(scope, transaction_style, request)
|
|
439
441
|
|
|
440
442
|
|
|
441
|
-
def _after_get_response(request):
|
|
442
|
-
# type: (WSGIRequest) -> None
|
|
443
|
+
def _after_get_response(request: WSGIRequest) -> None:
|
|
443
444
|
integration = sentry_sdk.get_client().get_integration(DjangoIntegration)
|
|
444
445
|
if integration is None or integration.transaction_style != "url":
|
|
445
446
|
return
|
|
@@ -448,8 +449,7 @@ def _after_get_response(request):
|
|
|
448
449
|
_attempt_resolve_again(request, scope, integration.transaction_style)
|
|
449
450
|
|
|
450
451
|
|
|
451
|
-
def _patch_get_response():
|
|
452
|
-
# type: () -> None
|
|
452
|
+
def _patch_get_response() -> None:
|
|
453
453
|
"""
|
|
454
454
|
patch get_response, because at that point we have the Django request object
|
|
455
455
|
"""
|
|
@@ -458,8 +458,9 @@ def _patch_get_response():
|
|
|
458
458
|
old_get_response = BaseHandler.get_response
|
|
459
459
|
|
|
460
460
|
@functools.wraps(old_get_response)
|
|
461
|
-
def sentry_patched_get_response(
|
|
462
|
-
|
|
461
|
+
def sentry_patched_get_response(
|
|
462
|
+
self: Any, request: WSGIRequest
|
|
463
|
+
) -> Union[HttpResponse, BaseException]:
|
|
463
464
|
_before_get_response(request)
|
|
464
465
|
rv = old_get_response(self, request)
|
|
465
466
|
_after_get_response(request)
|
|
@@ -473,10 +474,10 @@ def _patch_get_response():
|
|
|
473
474
|
patch_get_response_async(BaseHandler, _before_get_response)
|
|
474
475
|
|
|
475
476
|
|
|
476
|
-
def _make_wsgi_request_event_processor(
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
477
|
+
def _make_wsgi_request_event_processor(
|
|
478
|
+
weak_request: Callable[[], WSGIRequest], integration: DjangoIntegration
|
|
479
|
+
) -> EventProcessor:
|
|
480
|
+
def wsgi_request_event_processor(event: Event, hint: dict[str, Any]) -> Event:
|
|
480
481
|
# if the request is gone we are fine not logging the data from
|
|
481
482
|
# it. This might happen if the processor is pushed away to
|
|
482
483
|
# another thread.
|
|
@@ -501,8 +502,7 @@ def _make_wsgi_request_event_processor(weak_request, integration):
|
|
|
501
502
|
return wsgi_request_event_processor
|
|
502
503
|
|
|
503
504
|
|
|
504
|
-
def _got_request_exception(request=None, **kwargs):
|
|
505
|
-
# type: (WSGIRequest, **Any) -> None
|
|
505
|
+
def _got_request_exception(request: WSGIRequest = None, **kwargs: Any) -> None:
|
|
506
506
|
client = sentry_sdk.get_client()
|
|
507
507
|
integration = client.get_integration(DjangoIntegration)
|
|
508
508
|
if integration is None:
|
|
@@ -521,8 +521,7 @@ def _got_request_exception(request=None, **kwargs):
|
|
|
521
521
|
|
|
522
522
|
|
|
523
523
|
class DjangoRequestExtractor(RequestExtractor):
|
|
524
|
-
def __init__(self, request):
|
|
525
|
-
# type: (Union[WSGIRequest, ASGIRequest]) -> None
|
|
524
|
+
def __init__(self, request: Union[WSGIRequest, ASGIRequest]) -> None:
|
|
526
525
|
try:
|
|
527
526
|
drf_request = request._sentry_drf_request_backref()
|
|
528
527
|
if drf_request is not None:
|
|
@@ -531,18 +530,16 @@ class DjangoRequestExtractor(RequestExtractor):
|
|
|
531
530
|
pass
|
|
532
531
|
self.request = request
|
|
533
532
|
|
|
534
|
-
def env(self):
|
|
535
|
-
# type: () -> Dict[str, str]
|
|
533
|
+
def env(self) -> Dict[str, str]:
|
|
536
534
|
return self.request.META
|
|
537
535
|
|
|
538
|
-
def cookies(self):
|
|
539
|
-
# type: () -> Dict[str, Union[str, AnnotatedValue]]
|
|
536
|
+
def cookies(self) -> Dict[str, Union[str, AnnotatedValue]]:
|
|
540
537
|
privacy_cookies = [
|
|
541
538
|
django_settings.CSRF_COOKIE_NAME,
|
|
542
539
|
django_settings.SESSION_COOKIE_NAME,
|
|
543
540
|
]
|
|
544
541
|
|
|
545
|
-
clean_cookies
|
|
542
|
+
clean_cookies: Dict[str, Union[str, AnnotatedValue]] = {}
|
|
546
543
|
for key, val in self.request.COOKIES.items():
|
|
547
544
|
if key in privacy_cookies:
|
|
548
545
|
clean_cookies[key] = SENSITIVE_DATA_SUBSTITUTE
|
|
@@ -551,32 +548,26 @@ class DjangoRequestExtractor(RequestExtractor):
|
|
|
551
548
|
|
|
552
549
|
return clean_cookies
|
|
553
550
|
|
|
554
|
-
def raw_data(self):
|
|
555
|
-
# type: () -> bytes
|
|
551
|
+
def raw_data(self) -> bytes:
|
|
556
552
|
return self.request.body
|
|
557
553
|
|
|
558
|
-
def form(self):
|
|
559
|
-
# type: () -> QueryDict
|
|
554
|
+
def form(self) -> QueryDict:
|
|
560
555
|
return self.request.POST
|
|
561
556
|
|
|
562
|
-
def files(self):
|
|
563
|
-
# type: () -> MultiValueDict
|
|
557
|
+
def files(self) -> MultiValueDict:
|
|
564
558
|
return self.request.FILES
|
|
565
559
|
|
|
566
|
-
def size_of_file(self, file):
|
|
567
|
-
# type: (Any) -> int
|
|
560
|
+
def size_of_file(self, file: Any) -> int:
|
|
568
561
|
return file.size
|
|
569
562
|
|
|
570
|
-
def parsed_body(self):
|
|
571
|
-
# type: () -> Optional[Dict[str, Any]]
|
|
563
|
+
def parsed_body(self) -> Optional[Dict[str, Any]]:
|
|
572
564
|
try:
|
|
573
565
|
return self.request.data
|
|
574
566
|
except Exception:
|
|
575
567
|
return RequestExtractor.parsed_body(self)
|
|
576
568
|
|
|
577
569
|
|
|
578
|
-
def _set_user_info(request, event):
|
|
579
|
-
# type: (WSGIRequest, Event) -> None
|
|
570
|
+
def _set_user_info(request: WSGIRequest, event: Event) -> None:
|
|
580
571
|
user_info = event.setdefault("user", {})
|
|
581
572
|
|
|
582
573
|
user = getattr(request, "user", None)
|
|
@@ -600,8 +591,7 @@ def _set_user_info(request, event):
|
|
|
600
591
|
pass
|
|
601
592
|
|
|
602
593
|
|
|
603
|
-
def install_sql_hook():
|
|
604
|
-
# type: () -> None
|
|
594
|
+
def install_sql_hook() -> None:
|
|
605
595
|
"""If installed this causes Django's queries to be captured."""
|
|
606
596
|
try:
|
|
607
597
|
from django.db.backends.utils import CursorWrapper
|
|
@@ -615,8 +605,7 @@ def install_sql_hook():
|
|
|
615
605
|
real_connect = BaseDatabaseWrapper.connect
|
|
616
606
|
|
|
617
607
|
@ensure_integration_enabled(DjangoIntegration, real_execute)
|
|
618
|
-
def execute(self, sql, params=None):
|
|
619
|
-
# type: (CursorWrapper, Any, Optional[Any]) -> Any
|
|
608
|
+
def execute(self: CursorWrapper, sql: Any, params: Optional[Any] = None) -> Any:
|
|
620
609
|
with record_sql_queries(
|
|
621
610
|
cursor=self.cursor,
|
|
622
611
|
query=sql,
|
|
@@ -634,8 +623,7 @@ def install_sql_hook():
|
|
|
634
623
|
return result
|
|
635
624
|
|
|
636
625
|
@ensure_integration_enabled(DjangoIntegration, real_executemany)
|
|
637
|
-
def executemany(self, sql, param_list):
|
|
638
|
-
# type: (CursorWrapper, Any, List[Any]) -> Any
|
|
626
|
+
def executemany(self: CursorWrapper, sql: Any, param_list: List[Any]) -> Any:
|
|
639
627
|
with record_sql_queries(
|
|
640
628
|
cursor=self.cursor,
|
|
641
629
|
query=sql,
|
|
@@ -654,8 +642,7 @@ def install_sql_hook():
|
|
|
654
642
|
return result
|
|
655
643
|
|
|
656
644
|
@ensure_integration_enabled(DjangoIntegration, real_connect)
|
|
657
|
-
def connect(self):
|
|
658
|
-
# type: (BaseDatabaseWrapper) -> None
|
|
645
|
+
def connect(self: BaseDatabaseWrapper) -> None:
|
|
659
646
|
with capture_internal_exceptions():
|
|
660
647
|
sentry_sdk.add_breadcrumb(message="connect", category="query")
|
|
661
648
|
|
|
@@ -663,7 +650,7 @@ def install_sql_hook():
|
|
|
663
650
|
op=OP.DB,
|
|
664
651
|
name="connect",
|
|
665
652
|
origin=DjangoIntegration.origin_db,
|
|
666
|
-
|
|
653
|
+
only_as_child_span=True,
|
|
667
654
|
) as span:
|
|
668
655
|
_set_db_data(span, self)
|
|
669
656
|
return real_connect(self)
|
|
@@ -674,8 +661,7 @@ def install_sql_hook():
|
|
|
674
661
|
ignore_logger("django.db.backends")
|
|
675
662
|
|
|
676
663
|
|
|
677
|
-
def _set_db_data(span, cursor_or_db):
|
|
678
|
-
# type: (Span, Any) -> None
|
|
664
|
+
def _set_db_data(span: Span, cursor_or_db: Any) -> None:
|
|
679
665
|
db = cursor_or_db.db if hasattr(cursor_or_db, "db") else cursor_or_db
|
|
680
666
|
vendor = db.vendor
|
|
681
667
|
span.set_attribute(SPANDATA.DB_SYSTEM, vendor)
|
|
@@ -724,3 +710,12 @@ def _set_db_data(span, cursor_or_db):
|
|
|
724
710
|
server_socket_address = connection_params.get("unix_socket")
|
|
725
711
|
if server_socket_address is not None:
|
|
726
712
|
span.set_attribute(SPANDATA.SERVER_SOCKET_ADDRESS, server_socket_address)
|
|
713
|
+
|
|
714
|
+
|
|
715
|
+
def add_template_context_repr_sequence() -> None:
|
|
716
|
+
try:
|
|
717
|
+
from django.template.context import BaseContext
|
|
718
|
+
|
|
719
|
+
add_repr_sequence_type(BaseContext)
|
|
720
|
+
except Exception:
|
|
721
|
+
pass
|
|
@@ -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()
|
|
@@ -187,15 +184,14 @@ def wrap_async_view(callback):
|
|
|
187
184
|
op=OP.VIEW_RENDER,
|
|
188
185
|
name=request.resolver_match.view_name,
|
|
189
186
|
origin=DjangoIntegration.origin,
|
|
190
|
-
|
|
187
|
+
only_as_child_span=True,
|
|
191
188
|
):
|
|
192
189
|
return await callback(request, *args, **kwargs)
|
|
193
190
|
|
|
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__"):
|
|
@@ -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
|
|
|
@@ -54,7 +62,7 @@ def _patch_cache_method(cache, method_name, address, port):
|
|
|
54
62
|
op=op,
|
|
55
63
|
name=description,
|
|
56
64
|
origin=DjangoIntegration.origin,
|
|
57
|
-
|
|
65
|
+
only_as_child_span=True,
|
|
58
66
|
) as span:
|
|
59
67
|
value = original_method(*args, **kwargs)
|
|
60
68
|
|
|
@@ -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)
|