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
sentry_sdk/integrations/arq.py
CHANGED
|
@@ -5,7 +5,7 @@ from sentry_sdk.consts import OP, SPANSTATUS
|
|
|
5
5
|
from sentry_sdk.integrations import _check_minimum_version, DidNotEnable, Integration
|
|
6
6
|
from sentry_sdk.integrations.logging import ignore_logger
|
|
7
7
|
from sentry_sdk.scope import should_send_default_pii
|
|
8
|
-
from sentry_sdk.tracing import
|
|
8
|
+
from sentry_sdk.tracing import TransactionSource
|
|
9
9
|
from sentry_sdk.utils import (
|
|
10
10
|
capture_internal_exceptions,
|
|
11
11
|
ensure_integration_enabled,
|
|
@@ -37,6 +37,8 @@ if TYPE_CHECKING:
|
|
|
37
37
|
|
|
38
38
|
ARQ_CONTROL_FLOW_EXCEPTIONS = (JobExecutionFailed, Retry, RetryJob)
|
|
39
39
|
|
|
40
|
+
DEFAULT_TRANSACTION_NAME = "unknown arq task"
|
|
41
|
+
|
|
40
42
|
|
|
41
43
|
class ArqIntegration(Integration):
|
|
42
44
|
identifier = "arq"
|
|
@@ -76,7 +78,10 @@ def patch_enqueue_job():
|
|
|
76
78
|
return await old_enqueue_job(self, function, *args, **kwargs)
|
|
77
79
|
|
|
78
80
|
with sentry_sdk.start_span(
|
|
79
|
-
op=OP.QUEUE_SUBMIT_ARQ,
|
|
81
|
+
op=OP.QUEUE_SUBMIT_ARQ,
|
|
82
|
+
name=function,
|
|
83
|
+
origin=ArqIntegration.origin,
|
|
84
|
+
only_if_parent=True,
|
|
80
85
|
):
|
|
81
86
|
return await old_enqueue_job(self, function, *args, **kwargs)
|
|
82
87
|
|
|
@@ -96,18 +101,24 @@ def patch_run_job():
|
|
|
96
101
|
|
|
97
102
|
with sentry_sdk.isolation_scope() as scope:
|
|
98
103
|
scope._name = "arq"
|
|
104
|
+
scope.set_transaction_name(
|
|
105
|
+
DEFAULT_TRANSACTION_NAME,
|
|
106
|
+
source=TransactionSource.TASK,
|
|
107
|
+
)
|
|
99
108
|
scope.clear_breadcrumbs()
|
|
100
109
|
|
|
101
|
-
|
|
102
|
-
name="unknown arq task",
|
|
103
|
-
status="ok",
|
|
110
|
+
with sentry_sdk.start_span(
|
|
104
111
|
op=OP.QUEUE_TASK_ARQ,
|
|
112
|
+
name=DEFAULT_TRANSACTION_NAME,
|
|
105
113
|
source=TransactionSource.TASK,
|
|
106
114
|
origin=ArqIntegration.origin,
|
|
107
|
-
)
|
|
115
|
+
) as span:
|
|
116
|
+
return_value = await old_run_job(self, job_id, score)
|
|
117
|
+
|
|
118
|
+
if span.status is None:
|
|
119
|
+
span.set_status(SPANSTATUS.OK)
|
|
108
120
|
|
|
109
|
-
|
|
110
|
-
return await old_run_job(self, job_id, score)
|
|
121
|
+
return return_value
|
|
111
122
|
|
|
112
123
|
Worker.run_job = _sentry_run_job
|
|
113
124
|
|
|
@@ -116,12 +127,12 @@ def _capture_exception(exc_info):
|
|
|
116
127
|
# type: (ExcInfo) -> None
|
|
117
128
|
scope = sentry_sdk.get_current_scope()
|
|
118
129
|
|
|
119
|
-
if scope.
|
|
130
|
+
if scope.root_span is not None:
|
|
120
131
|
if exc_info[0] in ARQ_CONTROL_FLOW_EXCEPTIONS:
|
|
121
|
-
scope.
|
|
132
|
+
scope.root_span.set_status(SPANSTATUS.ABORTED)
|
|
122
133
|
return
|
|
123
134
|
|
|
124
|
-
scope.
|
|
135
|
+
scope.root_span.set_status(SPANSTATUS.INTERNAL_ERROR)
|
|
125
136
|
|
|
126
137
|
event, hint = event_from_exception(
|
|
127
138
|
exc_info,
|
|
@@ -138,8 +149,8 @@ def _make_event_processor(ctx, *args, **kwargs):
|
|
|
138
149
|
|
|
139
150
|
with capture_internal_exceptions():
|
|
140
151
|
scope = sentry_sdk.get_current_scope()
|
|
141
|
-
if scope.
|
|
142
|
-
scope.
|
|
152
|
+
if scope.root_span is not None:
|
|
153
|
+
scope.root_span.name = ctx["job_name"]
|
|
143
154
|
event["transaction"] = ctx["job_name"]
|
|
144
155
|
|
|
145
156
|
tags = event.setdefault("tags", {})
|
sentry_sdk/integrations/asgi.py
CHANGED
|
@@ -10,25 +10,22 @@ from copy import deepcopy
|
|
|
10
10
|
from functools import partial
|
|
11
11
|
|
|
12
12
|
import sentry_sdk
|
|
13
|
-
from sentry_sdk.
|
|
14
|
-
from sentry_sdk.consts import OP
|
|
13
|
+
from sentry_sdk.consts import OP, SOURCE_FOR_STYLE, TransactionSource
|
|
15
14
|
|
|
16
15
|
from sentry_sdk.integrations._asgi_common import (
|
|
17
16
|
_get_headers,
|
|
17
|
+
_get_query,
|
|
18
18
|
_get_request_data,
|
|
19
19
|
_get_url,
|
|
20
20
|
)
|
|
21
21
|
from sentry_sdk.integrations._wsgi_common import (
|
|
22
22
|
DEFAULT_HTTP_METHODS_TO_CAPTURE,
|
|
23
|
-
|
|
23
|
+
_request_headers_to_span_attributes,
|
|
24
24
|
)
|
|
25
25
|
from sentry_sdk.sessions import track_session
|
|
26
|
-
from sentry_sdk.tracing import (
|
|
27
|
-
SOURCE_FOR_STYLE,
|
|
28
|
-
TransactionSource,
|
|
29
|
-
)
|
|
30
26
|
from sentry_sdk.utils import (
|
|
31
27
|
ContextVar,
|
|
28
|
+
capture_internal_exceptions,
|
|
32
29
|
event_from_exception,
|
|
33
30
|
HAS_REAL_CONTEXTVARS,
|
|
34
31
|
CONTEXTVARS_ERROR_MESSAGE,
|
|
@@ -36,7 +33,6 @@ from sentry_sdk.utils import (
|
|
|
36
33
|
transaction_from_function,
|
|
37
34
|
_get_installed_modules,
|
|
38
35
|
)
|
|
39
|
-
from sentry_sdk.tracing import Transaction
|
|
40
36
|
|
|
41
37
|
from typing import TYPE_CHECKING
|
|
42
38
|
|
|
@@ -56,6 +52,14 @@ _DEFAULT_TRANSACTION_NAME = "generic ASGI request"
|
|
|
56
52
|
|
|
57
53
|
TRANSACTION_STYLE_VALUES = ("endpoint", "url")
|
|
58
54
|
|
|
55
|
+
ASGI_SCOPE_PROPERTY_TO_ATTRIBUTE = {
|
|
56
|
+
"http_version": "network.protocol.version",
|
|
57
|
+
"method": "http.request.method",
|
|
58
|
+
"path": "url.path",
|
|
59
|
+
"scheme": "url.scheme",
|
|
60
|
+
"type": "network.protocol.name",
|
|
61
|
+
}
|
|
62
|
+
|
|
59
63
|
|
|
60
64
|
def _capture_exception(exc, mechanism_type="asgi"):
|
|
61
65
|
# type: (Any, str) -> None
|
|
@@ -100,7 +104,7 @@ class SentryAsgiMiddleware:
|
|
|
100
104
|
unsafe_context_data=False, # type: bool
|
|
101
105
|
transaction_style="endpoint", # type: str
|
|
102
106
|
mechanism_type="asgi", # type: str
|
|
103
|
-
span_origin=
|
|
107
|
+
span_origin=None, # type: Optional[str]
|
|
104
108
|
http_methods_to_capture=DEFAULT_HTTP_METHODS_TO_CAPTURE, # type: Tuple[str, ...]
|
|
105
109
|
):
|
|
106
110
|
# type: (...) -> None
|
|
@@ -157,24 +161,40 @@ class SentryAsgiMiddleware:
|
|
|
157
161
|
# type: (Any, Any, Any) -> Any
|
|
158
162
|
return await self._run_app(scope, receive, send, asgi_version=3)
|
|
159
163
|
|
|
164
|
+
async def _run_original_app(self, scope, receive, send, asgi_version):
|
|
165
|
+
# type: (Any, Any, Any, Any, int) -> Any
|
|
166
|
+
try:
|
|
167
|
+
if asgi_version == 2:
|
|
168
|
+
return await self.app(scope)(receive, send)
|
|
169
|
+
else:
|
|
170
|
+
return await self.app(scope, receive, send)
|
|
171
|
+
|
|
172
|
+
except Exception as exc:
|
|
173
|
+
_capture_exception(exc, mechanism_type=self.mechanism_type)
|
|
174
|
+
raise exc from None
|
|
175
|
+
|
|
160
176
|
async def _run_app(self, scope, receive, send, asgi_version):
|
|
161
177
|
# type: (Any, Any, Any, Any, int) -> Any
|
|
162
178
|
is_recursive_asgi_middleware = _asgi_middleware_applied.get(False)
|
|
163
179
|
is_lifespan = scope["type"] == "lifespan"
|
|
164
180
|
if is_recursive_asgi_middleware or is_lifespan:
|
|
165
|
-
|
|
166
|
-
if asgi_version == 2:
|
|
167
|
-
return await self.app(scope)(receive, send)
|
|
168
|
-
else:
|
|
169
|
-
return await self.app(scope, receive, send)
|
|
170
|
-
|
|
171
|
-
except Exception as exc:
|
|
172
|
-
_capture_exception(exc, mechanism_type=self.mechanism_type)
|
|
173
|
-
raise exc from None
|
|
181
|
+
return await self._run_original_app(scope, receive, send, asgi_version)
|
|
174
182
|
|
|
175
183
|
_asgi_middleware_applied.set(True)
|
|
176
184
|
try:
|
|
177
185
|
with sentry_sdk.isolation_scope() as sentry_scope:
|
|
186
|
+
(
|
|
187
|
+
transaction_name,
|
|
188
|
+
transaction_source,
|
|
189
|
+
) = self._get_transaction_name_and_source(
|
|
190
|
+
self.transaction_style,
|
|
191
|
+
scope,
|
|
192
|
+
)
|
|
193
|
+
sentry_scope.set_transaction_name(
|
|
194
|
+
transaction_name,
|
|
195
|
+
source=transaction_source,
|
|
196
|
+
)
|
|
197
|
+
|
|
178
198
|
with track_session(sentry_scope, session_mode="request"):
|
|
179
199
|
sentry_scope.clear_breadcrumbs()
|
|
180
200
|
sentry_scope._name = "asgi"
|
|
@@ -182,81 +202,47 @@ class SentryAsgiMiddleware:
|
|
|
182
202
|
sentry_scope.add_event_processor(processor)
|
|
183
203
|
|
|
184
204
|
ty = scope["type"]
|
|
185
|
-
(
|
|
186
|
-
transaction_name,
|
|
187
|
-
transaction_source,
|
|
188
|
-
) = self._get_transaction_name_and_source(
|
|
189
|
-
self.transaction_style,
|
|
190
|
-
scope,
|
|
191
|
-
)
|
|
192
205
|
|
|
193
206
|
method = scope.get("method", "").upper()
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
name=transaction_name,
|
|
201
|
-
source=transaction_source,
|
|
202
|
-
origin=self.span_origin,
|
|
203
|
-
)
|
|
204
|
-
logger.debug(
|
|
205
|
-
"[ASGI] Created transaction (continuing trace): %s",
|
|
206
|
-
transaction,
|
|
207
|
-
)
|
|
208
|
-
else:
|
|
209
|
-
transaction = Transaction(
|
|
210
|
-
op=OP.HTTP_SERVER,
|
|
211
|
-
name=transaction_name,
|
|
212
|
-
source=transaction_source,
|
|
213
|
-
origin=self.span_origin,
|
|
214
|
-
)
|
|
215
|
-
logger.debug(
|
|
216
|
-
"[ASGI] Created transaction (new): %s", transaction
|
|
217
|
-
)
|
|
218
|
-
|
|
219
|
-
transaction.set_tag("asgi.type", ty)
|
|
220
|
-
logger.debug(
|
|
221
|
-
"[ASGI] Set transaction name and source on transaction: '%s' / '%s'",
|
|
222
|
-
transaction.name,
|
|
223
|
-
transaction.source,
|
|
207
|
+
should_trace = ty == "websocket" or (
|
|
208
|
+
ty == "http" and method in self.http_methods_to_capture
|
|
209
|
+
)
|
|
210
|
+
if not should_trace:
|
|
211
|
+
return await self._run_original_app(
|
|
212
|
+
scope, receive, send, asgi_version
|
|
224
213
|
)
|
|
225
214
|
|
|
226
|
-
with (
|
|
227
|
-
sentry_sdk.
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
215
|
+
with sentry_sdk.continue_trace(_get_headers(scope)):
|
|
216
|
+
with sentry_sdk.start_span(
|
|
217
|
+
op=(
|
|
218
|
+
OP.WEBSOCKET_SERVER
|
|
219
|
+
if ty == "websocket"
|
|
220
|
+
else OP.HTTP_SERVER
|
|
221
|
+
),
|
|
222
|
+
name=transaction_name,
|
|
223
|
+
source=transaction_source,
|
|
224
|
+
origin=self.span_origin,
|
|
225
|
+
attributes=_prepopulate_attributes(scope),
|
|
226
|
+
) as span:
|
|
227
|
+
if span is not None:
|
|
228
|
+
logger.debug("[ASGI] Started transaction: %s", span)
|
|
229
|
+
span.set_tag("asgi.type", ty)
|
|
236
230
|
|
|
237
231
|
async def _sentry_wrapped_send(event):
|
|
238
232
|
# type: (Dict[str, Any]) -> Any
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
233
|
+
is_http_response = (
|
|
234
|
+
event.get("type") == "http.response.start"
|
|
235
|
+
and span is not None
|
|
236
|
+
and "status" in event
|
|
237
|
+
)
|
|
238
|
+
if is_http_response:
|
|
239
|
+
span.set_http_status(event["status"])
|
|
246
240
|
|
|
247
241
|
return await send(event)
|
|
248
242
|
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
)
|
|
253
|
-
else:
|
|
254
|
-
return await self.app(
|
|
255
|
-
scope, receive, _sentry_wrapped_send
|
|
256
|
-
)
|
|
257
|
-
except Exception as exc:
|
|
258
|
-
_capture_exception(exc, mechanism_type=self.mechanism_type)
|
|
259
|
-
raise exc from None
|
|
243
|
+
return await self._run_original_app(
|
|
244
|
+
scope, receive, _sentry_wrapped_send, asgi_version
|
|
245
|
+
)
|
|
260
246
|
finally:
|
|
261
247
|
_asgi_middleware_applied.set(False)
|
|
262
248
|
|
|
@@ -335,3 +321,37 @@ class SentryAsgiMiddleware:
|
|
|
335
321
|
return name, source
|
|
336
322
|
|
|
337
323
|
return name, source
|
|
324
|
+
|
|
325
|
+
|
|
326
|
+
def _prepopulate_attributes(scope):
|
|
327
|
+
# type: (Any) -> dict[str, Any]
|
|
328
|
+
"""Unpack ASGI scope into serializable OTel attributes."""
|
|
329
|
+
scope = scope or {}
|
|
330
|
+
|
|
331
|
+
attributes = {}
|
|
332
|
+
for attr, key in ASGI_SCOPE_PROPERTY_TO_ATTRIBUTE.items():
|
|
333
|
+
if scope.get(attr):
|
|
334
|
+
attributes[key] = scope[attr]
|
|
335
|
+
|
|
336
|
+
for attr in ("client", "server"):
|
|
337
|
+
if scope.get(attr):
|
|
338
|
+
try:
|
|
339
|
+
host, port = scope[attr]
|
|
340
|
+
attributes[f"{attr}.address"] = host
|
|
341
|
+
if port is not None:
|
|
342
|
+
attributes[f"{attr}.port"] = port
|
|
343
|
+
except Exception:
|
|
344
|
+
pass
|
|
345
|
+
|
|
346
|
+
with capture_internal_exceptions():
|
|
347
|
+
full_url = _get_url(scope)
|
|
348
|
+
query = _get_query(scope)
|
|
349
|
+
if query:
|
|
350
|
+
attributes["url.query"] = query
|
|
351
|
+
full_url = f"{full_url}?{query}"
|
|
352
|
+
|
|
353
|
+
attributes["url.full"] = full_url
|
|
354
|
+
|
|
355
|
+
attributes.update(_request_headers_to_span_attributes(_get_headers(scope)))
|
|
356
|
+
|
|
357
|
+
return attributes
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
import contextlib
|
|
3
|
-
from typing import Any, TypeVar, Callable, Awaitable, Iterator
|
|
3
|
+
from typing import Any, TypeVar, Callable, Awaitable, Iterator, Optional
|
|
4
4
|
|
|
5
5
|
import sentry_sdk
|
|
6
6
|
from sentry_sdk.consts import OP, SPANDATA
|
|
@@ -8,6 +8,7 @@ from sentry_sdk.integrations import _check_minimum_version, Integration, DidNotE
|
|
|
8
8
|
from sentry_sdk.tracing import Span
|
|
9
9
|
from sentry_sdk.tracing_utils import add_query_source, record_sql_queries
|
|
10
10
|
from sentry_sdk.utils import (
|
|
11
|
+
_serialize_span_attribute,
|
|
11
12
|
ensure_integration_enabled,
|
|
12
13
|
parse_version,
|
|
13
14
|
capture_internal_exceptions,
|
|
@@ -38,7 +39,6 @@ class AsyncPGIntegration(Integration):
|
|
|
38
39
|
asyncpg.Connection.execute = _wrap_execute(
|
|
39
40
|
asyncpg.Connection.execute,
|
|
40
41
|
)
|
|
41
|
-
|
|
42
42
|
asyncpg.Connection._execute = _wrap_connection_method(
|
|
43
43
|
asyncpg.Connection._execute
|
|
44
44
|
)
|
|
@@ -78,8 +78,8 @@ def _wrap_execute(f: Callable[..., Awaitable[T]]) -> Callable[..., Awaitable[T]]
|
|
|
78
78
|
) as span:
|
|
79
79
|
res = await f(*args, **kwargs)
|
|
80
80
|
|
|
81
|
-
|
|
82
|
-
|
|
81
|
+
with capture_internal_exceptions():
|
|
82
|
+
add_query_source(span)
|
|
83
83
|
|
|
84
84
|
return res
|
|
85
85
|
|
|
@@ -121,10 +121,13 @@ def _wrap_connection_method(
|
|
|
121
121
|
async def _inner(*args: Any, **kwargs: Any) -> T:
|
|
122
122
|
if sentry_sdk.get_client().get_integration(AsyncPGIntegration) is None:
|
|
123
123
|
return await f(*args, **kwargs)
|
|
124
|
+
|
|
124
125
|
query = args[1]
|
|
125
126
|
params_list = args[2] if len(args) > 2 else None
|
|
127
|
+
|
|
126
128
|
with _record(None, query, params_list, executemany=executemany) as span:
|
|
127
|
-
|
|
129
|
+
data = _get_db_data(conn=args[0])
|
|
130
|
+
_set_on_span(span, data)
|
|
128
131
|
res = await f(*args, **kwargs)
|
|
129
132
|
|
|
130
133
|
return res
|
|
@@ -144,9 +147,10 @@ def _wrap_cursor_creation(f: Callable[..., T]) -> Callable[..., T]:
|
|
|
144
147
|
params_list,
|
|
145
148
|
executemany=False,
|
|
146
149
|
) as span:
|
|
147
|
-
|
|
150
|
+
data = _get_db_data(conn=args[0])
|
|
151
|
+
_set_on_span(span, data)
|
|
148
152
|
res = f(*args, **kwargs)
|
|
149
|
-
span.
|
|
153
|
+
span.set_attribute("db.cursor", _serialize_span_attribute(res))
|
|
150
154
|
|
|
151
155
|
return res
|
|
152
156
|
|
|
@@ -158,29 +162,24 @@ def _wrap_connect_addr(f: Callable[..., Awaitable[T]]) -> Callable[..., Awaitabl
|
|
|
158
162
|
if sentry_sdk.get_client().get_integration(AsyncPGIntegration) is None:
|
|
159
163
|
return await f(*args, **kwargs)
|
|
160
164
|
|
|
161
|
-
user = kwargs["params"].user
|
|
162
|
-
database = kwargs["params"].database
|
|
163
|
-
|
|
164
165
|
with sentry_sdk.start_span(
|
|
165
166
|
op=OP.DB,
|
|
166
167
|
name="connect",
|
|
167
168
|
origin=AsyncPGIntegration.origin,
|
|
169
|
+
only_if_parent=True,
|
|
168
170
|
) as span:
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
except IndexError:
|
|
176
|
-
pass
|
|
177
|
-
span.set_data(SPANDATA.DB_NAME, database)
|
|
178
|
-
span.set_data(SPANDATA.DB_USER, user)
|
|
171
|
+
data = _get_db_data(
|
|
172
|
+
addr=kwargs.get("addr"),
|
|
173
|
+
database=kwargs["params"].database,
|
|
174
|
+
user=kwargs["params"].user,
|
|
175
|
+
)
|
|
176
|
+
_set_on_span(span, data)
|
|
179
177
|
|
|
180
178
|
with capture_internal_exceptions():
|
|
181
179
|
sentry_sdk.add_breadcrumb(
|
|
182
|
-
message="connect", category="query", data=
|
|
180
|
+
message="connect", category="query", data=data
|
|
183
181
|
)
|
|
182
|
+
|
|
184
183
|
res = await f(*args, **kwargs)
|
|
185
184
|
|
|
186
185
|
return res
|
|
@@ -188,21 +187,37 @@ def _wrap_connect_addr(f: Callable[..., Awaitable[T]]) -> Callable[..., Awaitabl
|
|
|
188
187
|
return _inner
|
|
189
188
|
|
|
190
189
|
|
|
191
|
-
def
|
|
192
|
-
|
|
190
|
+
def _get_db_data(
|
|
191
|
+
conn: Any = None,
|
|
192
|
+
addr: Optional[tuple[str, ...]] = None,
|
|
193
|
+
database: Optional[str] = None,
|
|
194
|
+
user: Optional[str] = None,
|
|
195
|
+
) -> dict[str, str]:
|
|
196
|
+
if conn is not None:
|
|
197
|
+
addr = conn._addr
|
|
198
|
+
database = conn._params.database
|
|
199
|
+
user = conn._params.user
|
|
200
|
+
|
|
201
|
+
data = {
|
|
202
|
+
SPANDATA.DB_SYSTEM: "postgresql",
|
|
203
|
+
}
|
|
193
204
|
|
|
194
|
-
addr = conn._addr
|
|
195
205
|
if addr:
|
|
196
206
|
try:
|
|
197
|
-
|
|
198
|
-
|
|
207
|
+
data[SPANDATA.SERVER_ADDRESS] = addr[0]
|
|
208
|
+
data[SPANDATA.SERVER_PORT] = addr[1]
|
|
199
209
|
except IndexError:
|
|
200
210
|
pass
|
|
201
211
|
|
|
202
|
-
database = conn._params.database
|
|
203
212
|
if database:
|
|
204
|
-
|
|
213
|
+
data[SPANDATA.DB_NAME] = database
|
|
205
214
|
|
|
206
|
-
user = conn._params.user
|
|
207
215
|
if user:
|
|
208
|
-
|
|
216
|
+
data[SPANDATA.DB_USER] = user
|
|
217
|
+
|
|
218
|
+
return data
|
|
219
|
+
|
|
220
|
+
|
|
221
|
+
def _set_on_span(span: Span, data: dict[str, Any]) -> None:
|
|
222
|
+
for key, value in data.items():
|
|
223
|
+
span.set_attribute(key, value)
|