sentry-sdk 2.26.1__py2.py3-none-any.whl → 3.0.0a1__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 -8
- sentry_sdk/_compat.py +0 -1
- sentry_sdk/_init_implementation.py +6 -44
- sentry_sdk/_log_batcher.py +47 -28
- sentry_sdk/_types.py +8 -64
- sentry_sdk/ai/monitoring.py +14 -10
- sentry_sdk/ai/utils.py +1 -1
- sentry_sdk/api.py +69 -163
- sentry_sdk/client.py +25 -72
- sentry_sdk/consts.py +42 -23
- sentry_sdk/debug.py +0 -10
- sentry_sdk/envelope.py +2 -10
- sentry_sdk/feature_flags.py +5 -1
- sentry_sdk/integrations/__init__.py +5 -2
- sentry_sdk/integrations/_asgi_common.py +3 -3
- sentry_sdk/integrations/_wsgi_common.py +11 -40
- sentry_sdk/integrations/aiohttp.py +104 -57
- sentry_sdk/integrations/anthropic.py +10 -7
- sentry_sdk/integrations/arq.py +24 -13
- sentry_sdk/integrations/asgi.py +103 -83
- sentry_sdk/integrations/asyncio.py +1 -0
- sentry_sdk/integrations/asyncpg.py +45 -30
- sentry_sdk/integrations/aws_lambda.py +109 -92
- sentry_sdk/integrations/boto3.py +38 -9
- sentry_sdk/integrations/bottle.py +1 -1
- sentry_sdk/integrations/celery/__init__.py +48 -38
- sentry_sdk/integrations/clickhouse_driver.py +59 -28
- sentry_sdk/integrations/cohere.py +2 -0
- sentry_sdk/integrations/django/__init__.py +25 -46
- sentry_sdk/integrations/django/asgi.py +6 -2
- sentry_sdk/integrations/django/caching.py +13 -22
- sentry_sdk/integrations/django/middleware.py +1 -0
- sentry_sdk/integrations/django/signals_handlers.py +3 -1
- sentry_sdk/integrations/django/templates.py +8 -12
- sentry_sdk/integrations/django/transactions.py +1 -6
- sentry_sdk/integrations/django/views.py +5 -2
- sentry_sdk/integrations/falcon.py +7 -25
- sentry_sdk/integrations/fastapi.py +3 -3
- sentry_sdk/integrations/flask.py +1 -1
- sentry_sdk/integrations/gcp.py +63 -38
- sentry_sdk/integrations/graphene.py +6 -13
- sentry_sdk/integrations/grpc/aio/client.py +14 -8
- sentry_sdk/integrations/grpc/aio/server.py +19 -21
- sentry_sdk/integrations/grpc/client.py +8 -6
- sentry_sdk/integrations/grpc/server.py +12 -14
- sentry_sdk/integrations/httpx.py +47 -12
- sentry_sdk/integrations/huey.py +26 -22
- sentry_sdk/integrations/huggingface_hub.py +1 -0
- sentry_sdk/integrations/langchain.py +22 -15
- sentry_sdk/integrations/launchdarkly.py +3 -3
- sentry_sdk/integrations/litestar.py +4 -2
- sentry_sdk/integrations/logging.py +12 -3
- sentry_sdk/integrations/openai.py +2 -0
- sentry_sdk/integrations/openfeature.py +3 -5
- sentry_sdk/integrations/pymongo.py +18 -25
- sentry_sdk/integrations/pyramid.py +1 -1
- sentry_sdk/integrations/quart.py +3 -3
- sentry_sdk/integrations/ray.py +23 -17
- sentry_sdk/integrations/redis/_async_common.py +30 -18
- sentry_sdk/integrations/redis/_sync_common.py +28 -18
- sentry_sdk/integrations/redis/modules/caches.py +13 -10
- sentry_sdk/integrations/redis/modules/queries.py +14 -11
- sentry_sdk/integrations/redis/rb.py +4 -4
- sentry_sdk/integrations/redis/redis.py +6 -6
- sentry_sdk/integrations/redis/redis_cluster.py +18 -16
- sentry_sdk/integrations/redis/redis_py_cluster_legacy.py +4 -4
- sentry_sdk/integrations/redis/utils.py +63 -19
- sentry_sdk/integrations/rq.py +68 -23
- sentry_sdk/integrations/rust_tracing.py +28 -43
- sentry_sdk/integrations/sanic.py +23 -13
- sentry_sdk/integrations/socket.py +9 -5
- sentry_sdk/integrations/sqlalchemy.py +8 -8
- sentry_sdk/integrations/starlette.py +11 -31
- sentry_sdk/integrations/starlite.py +4 -2
- sentry_sdk/integrations/stdlib.py +56 -9
- sentry_sdk/integrations/strawberry.py +40 -59
- sentry_sdk/integrations/threading.py +10 -26
- sentry_sdk/integrations/tornado.py +57 -18
- sentry_sdk/integrations/trytond.py +4 -1
- sentry_sdk/integrations/unleash.py +2 -3
- sentry_sdk/integrations/wsgi.py +84 -38
- sentry_sdk/opentelemetry/__init__.py +9 -0
- sentry_sdk/opentelemetry/consts.py +33 -0
- sentry_sdk/opentelemetry/contextvars_context.py +73 -0
- sentry_sdk/{integrations/opentelemetry → opentelemetry}/propagator.py +19 -28
- sentry_sdk/opentelemetry/sampler.py +326 -0
- sentry_sdk/opentelemetry/scope.py +218 -0
- sentry_sdk/opentelemetry/span_processor.py +329 -0
- sentry_sdk/opentelemetry/tracing.py +35 -0
- sentry_sdk/opentelemetry/utils.py +476 -0
- sentry_sdk/profiler/__init__.py +0 -40
- sentry_sdk/profiler/continuous_profiler.py +1 -30
- sentry_sdk/profiler/transaction_profiler.py +5 -56
- sentry_sdk/scope.py +107 -351
- sentry_sdk/sessions.py +0 -87
- sentry_sdk/tracing.py +418 -1134
- sentry_sdk/tracing_utils.py +134 -169
- sentry_sdk/transport.py +4 -104
- sentry_sdk/types.py +26 -2
- sentry_sdk/utils.py +169 -152
- {sentry_sdk-2.26.1.dist-info → sentry_sdk-3.0.0a1.dist-info}/METADATA +3 -5
- sentry_sdk-3.0.0a1.dist-info/RECORD +154 -0
- {sentry_sdk-2.26.1.dist-info → sentry_sdk-3.0.0a1.dist-info}/WHEEL +1 -1
- sentry_sdk-3.0.0a1.dist-info/entry_points.txt +2 -0
- sentry_sdk/hub.py +0 -739
- sentry_sdk/integrations/opentelemetry/__init__.py +0 -7
- sentry_sdk/integrations/opentelemetry/consts.py +0 -5
- sentry_sdk/integrations/opentelemetry/integration.py +0 -58
- sentry_sdk/integrations/opentelemetry/span_processor.py +0 -391
- sentry_sdk/metrics.py +0 -965
- sentry_sdk-2.26.1.dist-info/RECORD +0 -152
- sentry_sdk-2.26.1.dist-info/entry_points.txt +0 -2
- {sentry_sdk-2.26.1.dist-info → sentry_sdk-3.0.0a1.dist-info}/licenses/LICENSE +0 -0
- {sentry_sdk-2.26.1.dist-info → sentry_sdk-3.0.0a1.dist-info}/top_level.txt +0 -0
|
@@ -3,9 +3,13 @@ from sentry_sdk.consts import OP, SPANDATA
|
|
|
3
3
|
from sentry_sdk.integrations import _check_minimum_version, Integration, DidNotEnable
|
|
4
4
|
from sentry_sdk.tracing import Span
|
|
5
5
|
from sentry_sdk.scope import should_send_default_pii
|
|
6
|
-
from sentry_sdk.utils import
|
|
6
|
+
from sentry_sdk.utils import (
|
|
7
|
+
_serialize_span_attribute,
|
|
8
|
+
capture_internal_exceptions,
|
|
9
|
+
ensure_integration_enabled,
|
|
10
|
+
)
|
|
7
11
|
|
|
8
|
-
from typing import TYPE_CHECKING, TypeVar
|
|
12
|
+
from typing import TYPE_CHECKING, cast, Any, Dict, TypeVar
|
|
9
13
|
|
|
10
14
|
# Hack to get new Python features working in older versions
|
|
11
15
|
# without introducing a hard dependency on `typing_extensions`
|
|
@@ -84,19 +88,23 @@ def _wrap_start(f: Callable[P, T]) -> Callable[P, T]:
|
|
|
84
88
|
op=OP.DB,
|
|
85
89
|
name=query,
|
|
86
90
|
origin=ClickhouseDriverIntegration.origin,
|
|
91
|
+
only_if_parent=True,
|
|
87
92
|
)
|
|
88
93
|
|
|
89
94
|
connection._sentry_span = span # type: ignore[attr-defined]
|
|
90
95
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
96
|
+
data = _get_db_data(connection)
|
|
97
|
+
data = cast("dict[str, Any]", data)
|
|
98
|
+
data["db.query.text"] = query
|
|
94
99
|
|
|
95
100
|
if query_id:
|
|
96
|
-
|
|
101
|
+
data["db.query_id"] = query_id
|
|
97
102
|
|
|
98
103
|
if params and should_send_default_pii():
|
|
99
|
-
|
|
104
|
+
data["db.params"] = params
|
|
105
|
+
|
|
106
|
+
connection._sentry_db_data = data # type: ignore[attr-defined]
|
|
107
|
+
_set_on_span(span, data)
|
|
100
108
|
|
|
101
109
|
# run the original code
|
|
102
110
|
ret = f(*args, **kwargs)
|
|
@@ -109,20 +117,32 @@ def _wrap_start(f: Callable[P, T]) -> Callable[P, T]:
|
|
|
109
117
|
def _wrap_end(f: Callable[P, T]) -> Callable[P, T]:
|
|
110
118
|
def _inner_end(*args: P.args, **kwargs: P.kwargs) -> T:
|
|
111
119
|
res = f(*args, **kwargs)
|
|
112
|
-
|
|
113
|
-
|
|
120
|
+
client = cast("clickhouse_driver.client.Client", args[0])
|
|
121
|
+
connection = client.connection
|
|
114
122
|
|
|
123
|
+
span = getattr(connection, "_sentry_span", None)
|
|
115
124
|
if span is not None:
|
|
125
|
+
data = getattr(connection, "_sentry_db_data", {})
|
|
126
|
+
|
|
116
127
|
if res is not None and should_send_default_pii():
|
|
117
|
-
|
|
128
|
+
data["db.result"] = res
|
|
129
|
+
span.set_attribute("db.result", _serialize_span_attribute(res))
|
|
118
130
|
|
|
119
131
|
with capture_internal_exceptions():
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
132
|
+
query = data.pop("db.query.text", None)
|
|
133
|
+
if query:
|
|
134
|
+
sentry_sdk.add_breadcrumb(
|
|
135
|
+
message=query, category="query", data=data
|
|
136
|
+
)
|
|
123
137
|
|
|
124
138
|
span.finish()
|
|
125
139
|
|
|
140
|
+
try:
|
|
141
|
+
del connection._sentry_db_data
|
|
142
|
+
del connection._sentry_span
|
|
143
|
+
except AttributeError:
|
|
144
|
+
pass
|
|
145
|
+
|
|
126
146
|
return res
|
|
127
147
|
|
|
128
148
|
return _inner_end
|
|
@@ -130,28 +150,39 @@ def _wrap_end(f: Callable[P, T]) -> Callable[P, T]:
|
|
|
130
150
|
|
|
131
151
|
def _wrap_send_data(f: Callable[P, T]) -> Callable[P, T]:
|
|
132
152
|
def _inner_send_data(*args: P.args, **kwargs: P.kwargs) -> T:
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
153
|
+
client = cast("clickhouse_driver.client.Client", args[0])
|
|
154
|
+
connection = client.connection
|
|
155
|
+
db_params_data = cast("list[Any]", args[2])
|
|
156
|
+
span = getattr(connection, "_sentry_span", None)
|
|
136
157
|
|
|
137
158
|
if span is not None:
|
|
138
|
-
|
|
159
|
+
data = _get_db_data(connection)
|
|
160
|
+
_set_on_span(span, data)
|
|
139
161
|
|
|
140
162
|
if should_send_default_pii():
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
163
|
+
saved_db_data = getattr(
|
|
164
|
+
connection, "_sentry_db_data", {}
|
|
165
|
+
) # type: dict[str, Any]
|
|
166
|
+
db_params = saved_db_data.get("db.params") or [] # type: list[Any]
|
|
167
|
+
db_params.extend(db_params_data)
|
|
168
|
+
saved_db_data["db.params"] = db_params
|
|
169
|
+
span.set_attribute("db.params", _serialize_span_attribute(db_params))
|
|
144
170
|
|
|
145
171
|
return f(*args, **kwargs)
|
|
146
172
|
|
|
147
173
|
return _inner_send_data
|
|
148
174
|
|
|
149
175
|
|
|
150
|
-
def
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
176
|
+
def _get_db_data(connection: clickhouse_driver.connection.Connection) -> Dict[str, str]:
|
|
177
|
+
return {
|
|
178
|
+
SPANDATA.DB_SYSTEM: "clickhouse",
|
|
179
|
+
SPANDATA.SERVER_ADDRESS: connection.host,
|
|
180
|
+
SPANDATA.SERVER_PORT: connection.port,
|
|
181
|
+
SPANDATA.DB_NAME: connection.database,
|
|
182
|
+
SPANDATA.DB_USER: connection.user,
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
def _set_on_span(span: Span, data: Dict[str, Any]) -> None:
|
|
187
|
+
for key, value in data.items():
|
|
188
|
+
span.set_attribute(key, _serialize_span_attribute(value))
|
|
@@ -147,6 +147,7 @@ def _wrap_chat(f, streaming):
|
|
|
147
147
|
op=consts.OP.COHERE_CHAT_COMPLETIONS_CREATE,
|
|
148
148
|
name="cohere.client.Chat",
|
|
149
149
|
origin=CohereIntegration.origin,
|
|
150
|
+
only_if_parent=True,
|
|
150
151
|
)
|
|
151
152
|
span.__enter__()
|
|
152
153
|
try:
|
|
@@ -233,6 +234,7 @@ def _wrap_embed(f):
|
|
|
233
234
|
op=consts.OP.COHERE_EMBEDDINGS_CREATE,
|
|
234
235
|
name="Cohere Embedding Creation",
|
|
235
236
|
origin=CohereIntegration.origin,
|
|
237
|
+
only_if_parent=True,
|
|
236
238
|
) as span:
|
|
237
239
|
if "texts" in kwargs and (
|
|
238
240
|
should_send_default_pii() and integration.include_prompts
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import functools
|
|
1
2
|
import inspect
|
|
2
3
|
import sys
|
|
3
4
|
import threading
|
|
@@ -5,10 +6,9 @@ import weakref
|
|
|
5
6
|
from importlib import import_module
|
|
6
7
|
|
|
7
8
|
import sentry_sdk
|
|
8
|
-
from sentry_sdk.consts import OP, SPANDATA
|
|
9
|
+
from sentry_sdk.consts import OP, SPANDATA, SOURCE_FOR_STYLE, TransactionSource
|
|
9
10
|
from sentry_sdk.scope import add_global_event_processor, should_send_default_pii
|
|
10
11
|
from sentry_sdk.serializer import add_global_repr_processor
|
|
11
|
-
from sentry_sdk.tracing import SOURCE_FOR_STYLE, TransactionSource
|
|
12
12
|
from sentry_sdk.tracing_utils import add_query_source, record_sql_queries
|
|
13
13
|
from sentry_sdk.utils import (
|
|
14
14
|
AnnotatedValue,
|
|
@@ -55,6 +55,7 @@ try:
|
|
|
55
55
|
except ImportError:
|
|
56
56
|
raise DidNotEnable("Django not installed")
|
|
57
57
|
|
|
58
|
+
from sentry_sdk.integrations.django.caching import patch_caching
|
|
58
59
|
from sentry_sdk.integrations.django.transactions import LEGACY_RESOLVER
|
|
59
60
|
from sentry_sdk.integrations.django.templates import (
|
|
60
61
|
get_template_frame_from_exception,
|
|
@@ -64,11 +65,6 @@ from sentry_sdk.integrations.django.middleware import patch_django_middlewares
|
|
|
64
65
|
from sentry_sdk.integrations.django.signals_handlers import patch_signals
|
|
65
66
|
from sentry_sdk.integrations.django.views import patch_views
|
|
66
67
|
|
|
67
|
-
if DJANGO_VERSION[:2] > (1, 8):
|
|
68
|
-
from sentry_sdk.integrations.django.caching import patch_caching
|
|
69
|
-
else:
|
|
70
|
-
patch_caching = None # type: ignore
|
|
71
|
-
|
|
72
68
|
from typing import TYPE_CHECKING
|
|
73
69
|
|
|
74
70
|
if TYPE_CHECKING:
|
|
@@ -89,19 +85,6 @@ if TYPE_CHECKING:
|
|
|
89
85
|
from sentry_sdk._types import Event, Hint, EventProcessor, NotImplementedType
|
|
90
86
|
|
|
91
87
|
|
|
92
|
-
if DJANGO_VERSION < (1, 10):
|
|
93
|
-
|
|
94
|
-
def is_authenticated(request_user):
|
|
95
|
-
# type: (Any) -> bool
|
|
96
|
-
return request_user.is_authenticated()
|
|
97
|
-
|
|
98
|
-
else:
|
|
99
|
-
|
|
100
|
-
def is_authenticated(request_user):
|
|
101
|
-
# type: (Any) -> bool
|
|
102
|
-
return request_user.is_authenticated
|
|
103
|
-
|
|
104
|
-
|
|
105
88
|
TRANSACTION_STYLE_VALUES = ("function_name", "url")
|
|
106
89
|
|
|
107
90
|
|
|
@@ -131,7 +114,7 @@ class DjangoIntegration(Integration):
|
|
|
131
114
|
transaction_style="url", # type: str
|
|
132
115
|
middleware_spans=True, # type: bool
|
|
133
116
|
signals_spans=True, # type: bool
|
|
134
|
-
cache_spans=
|
|
117
|
+
cache_spans=True, # type: bool
|
|
135
118
|
signals_denylist=None, # type: Optional[list[signals.Signal]]
|
|
136
119
|
http_methods_to_capture=DEFAULT_HTTP_METHODS_TO_CAPTURE, # type: tuple[str, ...]
|
|
137
120
|
):
|
|
@@ -321,6 +304,7 @@ def _patch_drf():
|
|
|
321
304
|
else:
|
|
322
305
|
old_drf_initial = APIView.initial
|
|
323
306
|
|
|
307
|
+
@functools.wraps(old_drf_initial)
|
|
324
308
|
def sentry_patched_drf_initial(self, request, *args, **kwargs):
|
|
325
309
|
# type: (APIView, Any, *Any, **Any) -> Any
|
|
326
310
|
with capture_internal_exceptions():
|
|
@@ -413,11 +397,13 @@ def _set_transaction_name_and_source(scope, transaction_style, request):
|
|
|
413
397
|
if hasattr(urlconf, "handler404"):
|
|
414
398
|
handler = urlconf.handler404
|
|
415
399
|
if isinstance(handler, str):
|
|
416
|
-
scope.
|
|
400
|
+
scope.set_transaction_name(handler)
|
|
417
401
|
else:
|
|
418
|
-
|
|
402
|
+
name = transaction_from_function(
|
|
419
403
|
getattr(handler, "view_class", handler)
|
|
420
404
|
)
|
|
405
|
+
if isinstance(name, str):
|
|
406
|
+
scope.set_transaction_name(name)
|
|
421
407
|
except Exception:
|
|
422
408
|
pass
|
|
423
409
|
|
|
@@ -471,6 +457,7 @@ def _patch_get_response():
|
|
|
471
457
|
|
|
472
458
|
old_get_response = BaseHandler.get_response
|
|
473
459
|
|
|
460
|
+
@functools.wraps(old_get_response)
|
|
474
461
|
def sentry_patched_get_response(self, request):
|
|
475
462
|
# type: (Any, WSGIRequest) -> Union[HttpResponse, BaseException]
|
|
476
463
|
_before_get_response(request)
|
|
@@ -594,7 +581,7 @@ def _set_user_info(request, event):
|
|
|
594
581
|
|
|
595
582
|
user = getattr(request, "user", None)
|
|
596
583
|
|
|
597
|
-
if user is None or not is_authenticated
|
|
584
|
+
if user is None or not user.is_authenticated:
|
|
598
585
|
return
|
|
599
586
|
|
|
600
587
|
try:
|
|
@@ -621,20 +608,11 @@ def install_sql_hook():
|
|
|
621
608
|
except ImportError:
|
|
622
609
|
from django.db.backends.util import CursorWrapper
|
|
623
610
|
|
|
624
|
-
|
|
625
|
-
# django 1.6 and 1.7 compatability
|
|
626
|
-
from django.db.backends import BaseDatabaseWrapper
|
|
627
|
-
except ImportError:
|
|
628
|
-
# django 1.8 or later
|
|
629
|
-
from django.db.backends.base.base import BaseDatabaseWrapper
|
|
611
|
+
from django.db.backends.base.base import BaseDatabaseWrapper
|
|
630
612
|
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
real_connect = BaseDatabaseWrapper.connect
|
|
635
|
-
except AttributeError:
|
|
636
|
-
# This won't work on Django versions < 1.6
|
|
637
|
-
return
|
|
613
|
+
real_execute = CursorWrapper.execute
|
|
614
|
+
real_executemany = CursorWrapper.executemany
|
|
615
|
+
real_connect = BaseDatabaseWrapper.connect
|
|
638
616
|
|
|
639
617
|
@ensure_integration_enabled(DjangoIntegration, real_execute)
|
|
640
618
|
def execute(self, sql, params=None):
|
|
@@ -650,8 +628,8 @@ def install_sql_hook():
|
|
|
650
628
|
_set_db_data(span, self)
|
|
651
629
|
result = real_execute(self, sql, params)
|
|
652
630
|
|
|
653
|
-
|
|
654
|
-
|
|
631
|
+
with capture_internal_exceptions():
|
|
632
|
+
add_query_source(span)
|
|
655
633
|
|
|
656
634
|
return result
|
|
657
635
|
|
|
@@ -670,8 +648,8 @@ def install_sql_hook():
|
|
|
670
648
|
|
|
671
649
|
result = real_executemany(self, sql, param_list)
|
|
672
650
|
|
|
673
|
-
|
|
674
|
-
|
|
651
|
+
with capture_internal_exceptions():
|
|
652
|
+
add_query_source(span)
|
|
675
653
|
|
|
676
654
|
return result
|
|
677
655
|
|
|
@@ -685,6 +663,7 @@ def install_sql_hook():
|
|
|
685
663
|
op=OP.DB,
|
|
686
664
|
name="connect",
|
|
687
665
|
origin=DjangoIntegration.origin_db,
|
|
666
|
+
only_if_parent=True,
|
|
688
667
|
) as span:
|
|
689
668
|
_set_db_data(span, self)
|
|
690
669
|
return real_connect(self)
|
|
@@ -699,7 +678,7 @@ def _set_db_data(span, cursor_or_db):
|
|
|
699
678
|
# type: (Span, Any) -> None
|
|
700
679
|
db = cursor_or_db.db if hasattr(cursor_or_db, "db") else cursor_or_db
|
|
701
680
|
vendor = db.vendor
|
|
702
|
-
span.
|
|
681
|
+
span.set_attribute(SPANDATA.DB_SYSTEM, vendor)
|
|
703
682
|
|
|
704
683
|
# Some custom backends override `__getattr__`, making it look like `cursor_or_db`
|
|
705
684
|
# actually has a `connection` and the `connection` has a `get_dsn_parameters`
|
|
@@ -732,16 +711,16 @@ def _set_db_data(span, cursor_or_db):
|
|
|
732
711
|
|
|
733
712
|
db_name = connection_params.get("dbname") or connection_params.get("database")
|
|
734
713
|
if db_name is not None:
|
|
735
|
-
span.
|
|
714
|
+
span.set_attribute(SPANDATA.DB_NAME, db_name)
|
|
736
715
|
|
|
737
716
|
server_address = connection_params.get("host")
|
|
738
717
|
if server_address is not None:
|
|
739
|
-
span.
|
|
718
|
+
span.set_attribute(SPANDATA.SERVER_ADDRESS, server_address)
|
|
740
719
|
|
|
741
720
|
server_port = connection_params.get("port")
|
|
742
721
|
if server_port is not None:
|
|
743
|
-
span.
|
|
722
|
+
span.set_attribute(SPANDATA.SERVER_PORT, str(server_port))
|
|
744
723
|
|
|
745
724
|
server_socket_address = connection_params.get("unix_socket")
|
|
746
725
|
if server_socket_address is not None:
|
|
747
|
-
span.
|
|
726
|
+
span.set_attribute(SPANDATA.SERVER_SOCKET_ADDRESS, server_socket_address)
|
|
@@ -88,6 +88,7 @@ def patch_django_asgi_handler_impl(cls):
|
|
|
88
88
|
|
|
89
89
|
old_app = cls.__call__
|
|
90
90
|
|
|
91
|
+
@functools.wraps(old_app)
|
|
91
92
|
async def sentry_patched_asgi_handler(self, scope, receive, send):
|
|
92
93
|
# type: (Any, Any, Any, Any) -> Any
|
|
93
94
|
integration = sentry_sdk.get_client().get_integration(DjangoIntegration)
|
|
@@ -125,6 +126,7 @@ def patch_get_response_async(cls, _before_get_response):
|
|
|
125
126
|
# type: (Any, Any) -> None
|
|
126
127
|
old_get_response_async = cls.get_response_async
|
|
127
128
|
|
|
129
|
+
@functools.wraps(old_get_response_async)
|
|
128
130
|
async def sentry_patched_get_response_async(self, request):
|
|
129
131
|
# type: (Any, Any) -> Union[HttpResponse, BaseException]
|
|
130
132
|
_before_get_response(request)
|
|
@@ -142,6 +144,7 @@ def patch_channels_asgi_handler_impl(cls):
|
|
|
142
144
|
if channels.__version__ < "3.0.0":
|
|
143
145
|
old_app = cls.__call__
|
|
144
146
|
|
|
147
|
+
@functools.wraps(old_app)
|
|
145
148
|
async def sentry_patched_asgi_handler(self, receive, send):
|
|
146
149
|
# type: (Any, Any, Any) -> Any
|
|
147
150
|
integration = sentry_sdk.get_client().get_integration(DjangoIntegration)
|
|
@@ -173,8 +176,8 @@ def wrap_async_view(callback):
|
|
|
173
176
|
async def sentry_wrapped_callback(request, *args, **kwargs):
|
|
174
177
|
# type: (Any, *Any, **Any) -> Any
|
|
175
178
|
current_scope = sentry_sdk.get_current_scope()
|
|
176
|
-
if current_scope.
|
|
177
|
-
current_scope.
|
|
179
|
+
if current_scope.root_span is not None:
|
|
180
|
+
current_scope.root_span.update_active_thread()
|
|
178
181
|
|
|
179
182
|
sentry_scope = sentry_sdk.get_isolation_scope()
|
|
180
183
|
if sentry_scope.profile is not None:
|
|
@@ -184,6 +187,7 @@ def wrap_async_view(callback):
|
|
|
184
187
|
op=OP.VIEW_RENDER,
|
|
185
188
|
name=request.resolver_match.view_name,
|
|
186
189
|
origin=DjangoIntegration.origin,
|
|
190
|
+
only_if_parent=True,
|
|
187
191
|
):
|
|
188
192
|
return await callback(request, *args, **kwargs)
|
|
189
193
|
|
|
@@ -54,27 +54,28 @@ def _patch_cache_method(cache, method_name, address, port):
|
|
|
54
54
|
op=op,
|
|
55
55
|
name=description,
|
|
56
56
|
origin=DjangoIntegration.origin,
|
|
57
|
+
only_if_parent=True,
|
|
57
58
|
) as span:
|
|
58
59
|
value = original_method(*args, **kwargs)
|
|
59
60
|
|
|
60
61
|
with capture_internal_exceptions():
|
|
61
62
|
if address is not None:
|
|
62
|
-
span.
|
|
63
|
+
span.set_attribute(SPANDATA.NETWORK_PEER_ADDRESS, address)
|
|
63
64
|
|
|
64
65
|
if port is not None:
|
|
65
|
-
span.
|
|
66
|
+
span.set_attribute(SPANDATA.NETWORK_PEER_PORT, port)
|
|
66
67
|
|
|
67
68
|
key = _get_safe_key(method_name, args, kwargs)
|
|
68
69
|
if key is not None:
|
|
69
|
-
span.
|
|
70
|
+
span.set_attribute(SPANDATA.CACHE_KEY, key)
|
|
70
71
|
|
|
71
72
|
item_size = None
|
|
72
73
|
if is_get_operation:
|
|
73
74
|
if value:
|
|
74
75
|
item_size = len(str(value))
|
|
75
|
-
span.
|
|
76
|
+
span.set_attribute(SPANDATA.CACHE_HIT, True)
|
|
76
77
|
else:
|
|
77
|
-
span.
|
|
78
|
+
span.set_attribute(SPANDATA.CACHE_HIT, False)
|
|
78
79
|
else: # TODO: We don't handle `get_or_set` which we should
|
|
79
80
|
arg_count = len(args)
|
|
80
81
|
if arg_count >= 2:
|
|
@@ -85,7 +86,7 @@ def _patch_cache_method(cache, method_name, address, port):
|
|
|
85
86
|
item_size = len(str(args[0]))
|
|
86
87
|
|
|
87
88
|
if item_size is not None:
|
|
88
|
-
span.
|
|
89
|
+
span.set_attribute(SPANDATA.CACHE_ITEM_SIZE, item_size)
|
|
89
90
|
|
|
90
91
|
return value
|
|
91
92
|
|
|
@@ -133,22 +134,10 @@ def _get_address_port(settings):
|
|
|
133
134
|
return address, int(port) if port is not None else None
|
|
134
135
|
|
|
135
136
|
|
|
136
|
-
def should_enable_cache_spans():
|
|
137
|
-
# type: () -> bool
|
|
138
|
-
from sentry_sdk.integrations.django import DjangoIntegration
|
|
139
|
-
|
|
140
|
-
client = sentry_sdk.get_client()
|
|
141
|
-
integration = client.get_integration(DjangoIntegration)
|
|
142
|
-
from django.conf import settings
|
|
143
|
-
|
|
144
|
-
return integration is not None and (
|
|
145
|
-
(client.spotlight is not None and settings.DEBUG is True)
|
|
146
|
-
or integration.cache_spans is True
|
|
147
|
-
)
|
|
148
|
-
|
|
149
|
-
|
|
150
137
|
def patch_caching():
|
|
151
138
|
# type: () -> None
|
|
139
|
+
from sentry_sdk.integrations.django import DjangoIntegration
|
|
140
|
+
|
|
152
141
|
if not hasattr(CacheHandler, "_sentry_patched"):
|
|
153
142
|
if DJANGO_VERSION < (3, 2):
|
|
154
143
|
original_get_item = CacheHandler.__getitem__
|
|
@@ -158,7 +147,8 @@ def patch_caching():
|
|
|
158
147
|
# type: (CacheHandler, str) -> Any
|
|
159
148
|
cache = original_get_item(self, alias)
|
|
160
149
|
|
|
161
|
-
|
|
150
|
+
integration = sentry_sdk.get_client().get_integration(DjangoIntegration)
|
|
151
|
+
if integration is not None and integration.cache_spans:
|
|
162
152
|
from django.conf import settings
|
|
163
153
|
|
|
164
154
|
address, port = _get_address_port(
|
|
@@ -180,7 +170,8 @@ def patch_caching():
|
|
|
180
170
|
# type: (CacheHandler, str) -> Any
|
|
181
171
|
cache = original_create_connection(self, alias)
|
|
182
172
|
|
|
183
|
-
|
|
173
|
+
integration = sentry_sdk.get_client().get_integration(DjangoIntegration)
|
|
174
|
+
if integration is not None and integration.cache_spans:
|
|
184
175
|
address, port = _get_address_port(self.settings[alias or "default"])
|
|
185
176
|
|
|
186
177
|
_patch_cache(cache, address, port)
|
|
@@ -89,6 +89,7 @@ def _wrap_middleware(middleware, middleware_name):
|
|
|
89
89
|
op=OP.MIDDLEWARE_DJANGO,
|
|
90
90
|
name=description,
|
|
91
91
|
origin=DjangoIntegration.origin,
|
|
92
|
+
only_if_parent=True,
|
|
92
93
|
)
|
|
93
94
|
middleware_span.set_tag("django.function_name", function_name)
|
|
94
95
|
middleware_span.set_tag("django.middleware_name", middleware_name)
|
|
@@ -50,6 +50,7 @@ def patch_signals():
|
|
|
50
50
|
|
|
51
51
|
old_live_receivers = Signal._live_receivers
|
|
52
52
|
|
|
53
|
+
@wraps(old_live_receivers)
|
|
53
54
|
def _sentry_live_receivers(self, sender):
|
|
54
55
|
# type: (Signal, Any) -> Union[tuple[list[Callable[..., Any]], list[Callable[..., Any]]], list[Callable[..., Any]]]
|
|
55
56
|
if DJANGO_VERSION >= (5, 0):
|
|
@@ -68,8 +69,9 @@ def patch_signals():
|
|
|
68
69
|
op=OP.EVENT_DJANGO,
|
|
69
70
|
name=signal_name,
|
|
70
71
|
origin=DjangoIntegration.origin,
|
|
72
|
+
only_if_parent=True,
|
|
71
73
|
) as span:
|
|
72
|
-
span.
|
|
74
|
+
span.set_attribute("signal", signal_name)
|
|
73
75
|
return receiver(*args, **kwargs)
|
|
74
76
|
|
|
75
77
|
return wrapper
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import functools
|
|
2
2
|
|
|
3
3
|
from django.template import TemplateSyntaxError
|
|
4
|
+
from django.template.base import Origin
|
|
4
5
|
from django.utils.safestring import mark_safe
|
|
5
|
-
from django import VERSION as DJANGO_VERSION
|
|
6
6
|
|
|
7
7
|
import sentry_sdk
|
|
8
8
|
from sentry_sdk.consts import OP
|
|
@@ -17,13 +17,6 @@ if TYPE_CHECKING:
|
|
|
17
17
|
from typing import Iterator
|
|
18
18
|
from typing import Tuple
|
|
19
19
|
|
|
20
|
-
try:
|
|
21
|
-
# support Django 1.9
|
|
22
|
-
from django.template.base import Origin
|
|
23
|
-
except ImportError:
|
|
24
|
-
# backward compatibility
|
|
25
|
-
from django.template.loader import LoaderOrigin as Origin
|
|
26
|
-
|
|
27
20
|
|
|
28
21
|
def get_template_frame_from_exception(exc_value):
|
|
29
22
|
# type: (Optional[BaseException]) -> Optional[Dict[str, Any]]
|
|
@@ -72,14 +65,15 @@ def patch_templates():
|
|
|
72
65
|
op=OP.TEMPLATE_RENDER,
|
|
73
66
|
name=_get_template_name_description(self.template_name),
|
|
74
67
|
origin=DjangoIntegration.origin,
|
|
68
|
+
only_if_parent=True,
|
|
75
69
|
) as span:
|
|
76
|
-
|
|
70
|
+
if isinstance(self.context_data, dict):
|
|
71
|
+
for k, v in self.context_data.items():
|
|
72
|
+
span.set_attribute(f"context.{k}", v)
|
|
77
73
|
return real_rendered_content.fget(self)
|
|
78
74
|
|
|
79
75
|
SimpleTemplateResponse.rendered_content = rendered_content
|
|
80
76
|
|
|
81
|
-
if DJANGO_VERSION < (1, 7):
|
|
82
|
-
return
|
|
83
77
|
import django.shortcuts
|
|
84
78
|
|
|
85
79
|
real_render = django.shortcuts.render
|
|
@@ -100,8 +94,10 @@ def patch_templates():
|
|
|
100
94
|
op=OP.TEMPLATE_RENDER,
|
|
101
95
|
name=_get_template_name_description(template_name),
|
|
102
96
|
origin=DjangoIntegration.origin,
|
|
97
|
+
only_if_parent=True,
|
|
103
98
|
) as span:
|
|
104
|
-
|
|
99
|
+
for k, v in context.items():
|
|
100
|
+
span.set_attribute(f"context.{k}", v)
|
|
105
101
|
return real_render(request, template_name, context, *args, **kwargs)
|
|
106
102
|
|
|
107
103
|
django.shortcuts.render = render
|
|
@@ -19,12 +19,7 @@ if TYPE_CHECKING:
|
|
|
19
19
|
from typing import Union
|
|
20
20
|
from re import Pattern
|
|
21
21
|
|
|
22
|
-
from django import
|
|
23
|
-
|
|
24
|
-
if DJANGO_VERSION >= (2, 0):
|
|
25
|
-
from django.urls.resolvers import RoutePattern
|
|
26
|
-
else:
|
|
27
|
-
RoutePattern = None
|
|
22
|
+
from django.urls.resolvers import RoutePattern
|
|
28
23
|
|
|
29
24
|
try:
|
|
30
25
|
from django.urls import get_resolver
|
|
@@ -31,12 +31,14 @@ def patch_views():
|
|
|
31
31
|
old_make_view_atomic = BaseHandler.make_view_atomic
|
|
32
32
|
old_render = SimpleTemplateResponse.render
|
|
33
33
|
|
|
34
|
+
@functools.wraps(old_render)
|
|
34
35
|
def sentry_patched_render(self):
|
|
35
36
|
# type: (SimpleTemplateResponse) -> Any
|
|
36
37
|
with sentry_sdk.start_span(
|
|
37
38
|
op=OP.VIEW_RESPONSE_RENDER,
|
|
38
39
|
name="serialize response",
|
|
39
40
|
origin=DjangoIntegration.origin,
|
|
41
|
+
only_if_parent=True,
|
|
40
42
|
):
|
|
41
43
|
return old_render(self)
|
|
42
44
|
|
|
@@ -77,8 +79,8 @@ def _wrap_sync_view(callback):
|
|
|
77
79
|
def sentry_wrapped_callback(request, *args, **kwargs):
|
|
78
80
|
# type: (Any, *Any, **Any) -> Any
|
|
79
81
|
current_scope = sentry_sdk.get_current_scope()
|
|
80
|
-
if current_scope.
|
|
81
|
-
current_scope.
|
|
82
|
+
if current_scope.root_span is not None:
|
|
83
|
+
current_scope.root_span.update_active_thread()
|
|
82
84
|
|
|
83
85
|
sentry_scope = sentry_sdk.get_isolation_scope()
|
|
84
86
|
# set the active thread id to the handler thread for sync views
|
|
@@ -90,6 +92,7 @@ def _wrap_sync_view(callback):
|
|
|
90
92
|
op=OP.VIEW_RENDER,
|
|
91
93
|
name=request.resolver_match.view_name,
|
|
92
94
|
origin=DjangoIntegration.origin,
|
|
95
|
+
only_if_parent=True,
|
|
93
96
|
):
|
|
94
97
|
return callback(request, *args, **kwargs)
|
|
95
98
|
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import sentry_sdk
|
|
2
|
+
from sentry_sdk.consts import SOURCE_FOR_STYLE
|
|
2
3
|
from sentry_sdk.integrations import _check_minimum_version, Integration, DidNotEnable
|
|
3
4
|
from sentry_sdk.integrations._wsgi_common import RequestExtractor
|
|
4
5
|
from sentry_sdk.integrations.wsgi import SentryWsgiMiddleware
|
|
5
|
-
from sentry_sdk.tracing import SOURCE_FOR_STYLE
|
|
6
6
|
from sentry_sdk.utils import (
|
|
7
7
|
capture_internal_exceptions,
|
|
8
8
|
ensure_integration_enabled,
|
|
@@ -19,8 +19,6 @@ if TYPE_CHECKING:
|
|
|
19
19
|
|
|
20
20
|
from sentry_sdk._types import Event, EventProcessor
|
|
21
21
|
|
|
22
|
-
# In Falcon 3.0 `falcon.api_helpers` is renamed to `falcon.app_helpers`
|
|
23
|
-
# and `falcon.API` to `falcon.App`
|
|
24
22
|
|
|
25
23
|
try:
|
|
26
24
|
import falcon # type: ignore
|
|
@@ -29,24 +27,15 @@ try:
|
|
|
29
27
|
except ImportError:
|
|
30
28
|
raise DidNotEnable("Falcon not installed")
|
|
31
29
|
|
|
32
|
-
|
|
33
|
-
import falcon.app_helpers # type: ignore
|
|
34
|
-
|
|
35
|
-
falcon_helpers = falcon.app_helpers
|
|
36
|
-
falcon_app_class = falcon.App
|
|
37
|
-
FALCON3 = True
|
|
38
|
-
except ImportError:
|
|
39
|
-
import falcon.api_helpers # type: ignore
|
|
30
|
+
import falcon.app_helpers # type: ignore
|
|
40
31
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
FALCON3 = False
|
|
32
|
+
falcon_helpers = falcon.app_helpers
|
|
33
|
+
falcon_app_class = falcon.App
|
|
44
34
|
|
|
45
35
|
|
|
46
36
|
_FALCON_UNSET = None # type: Optional[object]
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
from falcon.request import _UNSET as _FALCON_UNSET # type: ignore[import-not-found, no-redef]
|
|
37
|
+
with capture_internal_exceptions():
|
|
38
|
+
from falcon.request import _UNSET as _FALCON_UNSET # type: ignore[import-not-found, no-redef]
|
|
50
39
|
|
|
51
40
|
|
|
52
41
|
class FalconRequestExtractor(RequestExtractor):
|
|
@@ -232,14 +221,7 @@ def _exception_leads_to_http_5xx(ex, response):
|
|
|
232
221
|
ex, (falcon.HTTPError, falcon.http_status.HTTPStatus)
|
|
233
222
|
)
|
|
234
223
|
|
|
235
|
-
|
|
236
|
-
# at the stage where we capture it is listed as 200, even though we would expect to see a 500
|
|
237
|
-
# status. Since at the time of this change, Falcon 2 is ca. 4 years old, we have decided to
|
|
238
|
-
# only perform this check on Falcon 3+, despite the risk that some handled errors might be
|
|
239
|
-
# reported to Sentry as unhandled on Falcon 2.
|
|
240
|
-
return (is_server_error or is_unhandled_error) and (
|
|
241
|
-
not FALCON3 or _has_http_5xx_status(response)
|
|
242
|
-
)
|
|
224
|
+
return (is_server_error or is_unhandled_error) and _has_http_5xx_status(response)
|
|
243
225
|
|
|
244
226
|
|
|
245
227
|
def _has_http_5xx_status(response):
|