sentry-sdk 2.30.0__py2.py3-none-any.whl → 3.0.0a2__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 +3 -8
- sentry_sdk/_compat.py +0 -1
- sentry_sdk/_init_implementation.py +6 -44
- sentry_sdk/_types.py +2 -64
- sentry_sdk/ai/monitoring.py +14 -10
- sentry_sdk/ai/utils.py +1 -1
- sentry_sdk/api.py +56 -169
- sentry_sdk/client.py +27 -72
- sentry_sdk/consts.py +60 -23
- sentry_sdk/debug.py +0 -10
- sentry_sdk/envelope.py +1 -3
- sentry_sdk/feature_flags.py +1 -1
- sentry_sdk/integrations/__init__.py +4 -2
- sentry_sdk/integrations/_asgi_common.py +5 -6
- 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 +102 -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 +51 -41
- 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/litestar.py +4 -2
- sentry_sdk/integrations/logging.py +7 -2
- sentry_sdk/integrations/openai.py +2 -0
- 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 +29 -18
- sentry_sdk/integrations/redis/_sync_common.py +28 -19
- 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 -18
- sentry_sdk/integrations/redis/redis_py_cluster_legacy.py +4 -4
- sentry_sdk/integrations/redis/utils.py +64 -24
- 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/wsgi.py +84 -38
- sentry_sdk/opentelemetry/__init__.py +9 -0
- sentry_sdk/opentelemetry/consts.py +33 -0
- sentry_sdk/opentelemetry/contextvars_context.py +81 -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 +335 -0
- sentry_sdk/opentelemetry/tracing.py +59 -0
- sentry_sdk/opentelemetry/utils.py +484 -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 +108 -361
- sentry_sdk/sessions.py +0 -87
- sentry_sdk/tracing.py +415 -1161
- sentry_sdk/tracing_utils.py +130 -166
- sentry_sdk/transport.py +4 -104
- sentry_sdk/utils.py +169 -152
- {sentry_sdk-2.30.0.dist-info → sentry_sdk-3.0.0a2.dist-info}/METADATA +3 -5
- sentry_sdk-3.0.0a2.dist-info/RECORD +154 -0
- sentry_sdk-3.0.0a2.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.30.0.dist-info/RECORD +0 -152
- sentry_sdk-2.30.0.dist-info/entry_points.txt +0 -2
- {sentry_sdk-2.30.0.dist-info → sentry_sdk-3.0.0a2.dist-info}/WHEEL +0 -0
- {sentry_sdk-2.30.0.dist-info → sentry_sdk-3.0.0a2.dist-info}/licenses/LICENSE +0 -0
- {sentry_sdk-2.30.0.dist-info → sentry_sdk-3.0.0a2.dist-info}/top_level.txt +0 -0
|
@@ -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)
|
|
@@ -5,9 +5,9 @@ import sys
|
|
|
5
5
|
from copy import deepcopy
|
|
6
6
|
from datetime import datetime, timedelta, timezone
|
|
7
7
|
from os import environ
|
|
8
|
+
from urllib.parse import urlencode
|
|
8
9
|
|
|
9
10
|
import sentry_sdk
|
|
10
|
-
from sentry_sdk.api import continue_trace
|
|
11
11
|
from sentry_sdk.consts import OP
|
|
12
12
|
from sentry_sdk.scope import should_send_default_pii
|
|
13
13
|
from sentry_sdk.tracing import TransactionSource
|
|
@@ -21,7 +21,10 @@ from sentry_sdk.utils import (
|
|
|
21
21
|
reraise,
|
|
22
22
|
)
|
|
23
23
|
from sentry_sdk.integrations import Integration
|
|
24
|
-
from sentry_sdk.integrations._wsgi_common import
|
|
24
|
+
from sentry_sdk.integrations._wsgi_common import (
|
|
25
|
+
_filter_headers,
|
|
26
|
+
_request_headers_to_span_attributes,
|
|
27
|
+
)
|
|
25
28
|
|
|
26
29
|
from typing import TYPE_CHECKING
|
|
27
30
|
|
|
@@ -40,6 +43,17 @@ TIMEOUT_WARNING_BUFFER = 1500 # Buffer time required to send timeout warning to
|
|
|
40
43
|
MILLIS_TO_SECONDS = 1000.0
|
|
41
44
|
|
|
42
45
|
|
|
46
|
+
EVENT_TO_ATTRIBUTES = {
|
|
47
|
+
"httpMethod": "http.request.method",
|
|
48
|
+
"queryStringParameters": "url.query",
|
|
49
|
+
"path": "url.path",
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
CONTEXT_TO_ATTRIBUTES = {
|
|
53
|
+
"function_name": "faas.name",
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
|
|
43
57
|
def _wrap_init_error(init_error):
|
|
44
58
|
# type: (F) -> F
|
|
45
59
|
@ensure_integration_enabled(AwsLambdaIntegration, init_error)
|
|
@@ -110,6 +124,9 @@ def _wrap_handler(handler):
|
|
|
110
124
|
configured_time = aws_context.get_remaining_time_in_millis()
|
|
111
125
|
|
|
112
126
|
with sentry_sdk.isolation_scope() as scope:
|
|
127
|
+
scope.set_transaction_name(
|
|
128
|
+
aws_context.function_name, source=TransactionSource.COMPONENT
|
|
129
|
+
)
|
|
113
130
|
timeout_thread = None
|
|
114
131
|
with capture_internal_exceptions():
|
|
115
132
|
scope.clear_breadcrumbs()
|
|
@@ -149,34 +166,28 @@ def _wrap_handler(handler):
|
|
|
149
166
|
if not isinstance(headers, dict):
|
|
150
167
|
headers = {}
|
|
151
168
|
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
)
|
|
175
|
-
sentry_sdk.capture_event(sentry_event, hint=hint)
|
|
176
|
-
reraise(*exc_info)
|
|
177
|
-
finally:
|
|
178
|
-
if timeout_thread:
|
|
179
|
-
timeout_thread.stop()
|
|
169
|
+
with sentry_sdk.continue_trace(headers):
|
|
170
|
+
with sentry_sdk.start_span(
|
|
171
|
+
op=OP.FUNCTION_AWS,
|
|
172
|
+
name=aws_context.function_name,
|
|
173
|
+
source=TransactionSource.COMPONENT,
|
|
174
|
+
origin=AwsLambdaIntegration.origin,
|
|
175
|
+
attributes=_prepopulate_attributes(request_data, aws_context),
|
|
176
|
+
):
|
|
177
|
+
try:
|
|
178
|
+
return handler(aws_event, aws_context, *args, **kwargs)
|
|
179
|
+
except Exception:
|
|
180
|
+
exc_info = sys.exc_info()
|
|
181
|
+
sentry_event, hint = event_from_exception(
|
|
182
|
+
exc_info,
|
|
183
|
+
client_options=client.options,
|
|
184
|
+
mechanism={"type": "aws_lambda", "handled": False},
|
|
185
|
+
)
|
|
186
|
+
sentry_sdk.capture_event(sentry_event, hint=hint)
|
|
187
|
+
reraise(*exc_info)
|
|
188
|
+
finally:
|
|
189
|
+
if timeout_thread:
|
|
190
|
+
timeout_thread.stop()
|
|
180
191
|
|
|
181
192
|
return sentry_handler # type: ignore
|
|
182
193
|
|
|
@@ -219,77 +230,44 @@ class AwsLambdaIntegration(Integration):
|
|
|
219
230
|
)
|
|
220
231
|
return
|
|
221
232
|
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
old_handle_event_request = lambda_bootstrap.handle_event_request
|
|
226
|
-
|
|
227
|
-
def sentry_handle_event_request(request_handler, *args, **kwargs):
|
|
228
|
-
# type: (Any, *Any, **Any) -> Any
|
|
229
|
-
request_handler = _wrap_handler(request_handler)
|
|
230
|
-
return old_handle_event_request(request_handler, *args, **kwargs)
|
|
233
|
+
lambda_bootstrap.LambdaRuntimeClient.post_init_error = _wrap_init_error(
|
|
234
|
+
lambda_bootstrap.LambdaRuntimeClient.post_init_error
|
|
235
|
+
)
|
|
231
236
|
|
|
232
|
-
|
|
237
|
+
old_handle_event_request = lambda_bootstrap.handle_event_request
|
|
233
238
|
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
lambda_bootstrap.handle_http_request = sentry_handle_http_request
|
|
239
|
+
def sentry_handle_event_request( # type: ignore
|
|
240
|
+
lambda_runtime_client, request_handler, *args, **kwargs
|
|
241
|
+
):
|
|
242
|
+
request_handler = _wrap_handler(request_handler)
|
|
243
|
+
return old_handle_event_request(
|
|
244
|
+
lambda_runtime_client, request_handler, *args, **kwargs
|
|
245
|
+
)
|
|
242
246
|
|
|
243
|
-
|
|
244
|
-
# SDK is initialized inside of the handler
|
|
247
|
+
lambda_bootstrap.handle_event_request = sentry_handle_event_request
|
|
245
248
|
|
|
246
|
-
|
|
249
|
+
# Patch the runtime client to drain the queue. This should work
|
|
250
|
+
# even when the SDK is initialized inside of the handler
|
|
247
251
|
|
|
248
|
-
|
|
252
|
+
def _wrap_post_function(f):
|
|
253
|
+
# type: (F) -> F
|
|
254
|
+
def inner(*args, **kwargs):
|
|
249
255
|
# type: (*Any, **Any) -> Any
|
|
250
256
|
_drain_queue()
|
|
251
|
-
return
|
|
257
|
+
return f(*args, **kwargs)
|
|
252
258
|
|
|
253
|
-
|
|
254
|
-
else:
|
|
255
|
-
lambda_bootstrap.LambdaRuntimeClient.post_init_error = _wrap_init_error(
|
|
256
|
-
lambda_bootstrap.LambdaRuntimeClient.post_init_error
|
|
257
|
-
)
|
|
259
|
+
return inner # type: ignore
|
|
258
260
|
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
lambda_runtime_client, request_handler, *args, **kwargs
|
|
263
|
-
):
|
|
264
|
-
request_handler = _wrap_handler(request_handler)
|
|
265
|
-
return old_handle_event_request(
|
|
266
|
-
lambda_runtime_client, request_handler, *args, **kwargs
|
|
267
|
-
)
|
|
268
|
-
|
|
269
|
-
lambda_bootstrap.handle_event_request = sentry_handle_event_request
|
|
270
|
-
|
|
271
|
-
# Patch the runtime client to drain the queue. This should work
|
|
272
|
-
# even when the SDK is initialized inside of the handler
|
|
273
|
-
|
|
274
|
-
def _wrap_post_function(f):
|
|
275
|
-
# type: (F) -> F
|
|
276
|
-
def inner(*args, **kwargs):
|
|
277
|
-
# type: (*Any, **Any) -> Any
|
|
278
|
-
_drain_queue()
|
|
279
|
-
return f(*args, **kwargs)
|
|
280
|
-
|
|
281
|
-
return inner # type: ignore
|
|
282
|
-
|
|
283
|
-
lambda_bootstrap.LambdaRuntimeClient.post_invocation_result = (
|
|
284
|
-
_wrap_post_function(
|
|
285
|
-
lambda_bootstrap.LambdaRuntimeClient.post_invocation_result
|
|
286
|
-
)
|
|
261
|
+
lambda_bootstrap.LambdaRuntimeClient.post_invocation_result = (
|
|
262
|
+
_wrap_post_function(
|
|
263
|
+
lambda_bootstrap.LambdaRuntimeClient.post_invocation_result
|
|
287
264
|
)
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
265
|
+
)
|
|
266
|
+
lambda_bootstrap.LambdaRuntimeClient.post_invocation_error = (
|
|
267
|
+
_wrap_post_function(
|
|
268
|
+
lambda_bootstrap.LambdaRuntimeClient.post_invocation_error
|
|
292
269
|
)
|
|
270
|
+
)
|
|
293
271
|
|
|
294
272
|
|
|
295
273
|
def get_lambda_bootstrap():
|
|
@@ -362,7 +340,7 @@ def _make_request_event_processor(aws_event, aws_context, configured_timeout):
|
|
|
362
340
|
request["url"] = _get_url(aws_event, aws_context)
|
|
363
341
|
|
|
364
342
|
if "queryStringParameters" in aws_event:
|
|
365
|
-
request["query_string"] = aws_event["queryStringParameters"]
|
|
343
|
+
request["query_string"] = urlencode(aws_event["queryStringParameters"])
|
|
366
344
|
|
|
367
345
|
if "headers" in aws_event:
|
|
368
346
|
request["headers"] = _filter_headers(aws_event["headers"])
|
|
@@ -402,7 +380,9 @@ def _get_url(aws_event, aws_context):
|
|
|
402
380
|
path = aws_event.get("path", None)
|
|
403
381
|
|
|
404
382
|
headers = aws_event.get("headers")
|
|
405
|
-
|
|
383
|
+
# Some AWS Services (ie. EventBridge) set headers as a list
|
|
384
|
+
# or None, so we must ensure it is a dict
|
|
385
|
+
if not isinstance(headers, dict):
|
|
406
386
|
headers = {}
|
|
407
387
|
|
|
408
388
|
host = headers.get("Host", None)
|
|
@@ -497,3 +477,40 @@ def _event_from_error_json(error_json):
|
|
|
497
477
|
} # type: Event
|
|
498
478
|
|
|
499
479
|
return event
|
|
480
|
+
|
|
481
|
+
|
|
482
|
+
def _prepopulate_attributes(aws_event, aws_context):
|
|
483
|
+
# type: (Any, Any) -> dict[str, Any]
|
|
484
|
+
attributes = {
|
|
485
|
+
"cloud.provider": "aws",
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
for prop, attr in EVENT_TO_ATTRIBUTES.items():
|
|
489
|
+
if aws_event.get(prop) is not None:
|
|
490
|
+
if prop == "queryStringParameters":
|
|
491
|
+
attributes[attr] = urlencode(aws_event[prop])
|
|
492
|
+
else:
|
|
493
|
+
attributes[attr] = aws_event[prop]
|
|
494
|
+
|
|
495
|
+
for prop, attr in CONTEXT_TO_ATTRIBUTES.items():
|
|
496
|
+
if getattr(aws_context, prop, None) is not None:
|
|
497
|
+
attributes[attr] = getattr(aws_context, prop)
|
|
498
|
+
|
|
499
|
+
url = _get_url(aws_event, aws_context)
|
|
500
|
+
if url:
|
|
501
|
+
if aws_event.get("queryStringParameters"):
|
|
502
|
+
url += f"?{urlencode(aws_event['queryStringParameters'])}"
|
|
503
|
+
attributes["url.full"] = url
|
|
504
|
+
|
|
505
|
+
headers = {}
|
|
506
|
+
if aws_event.get("headers") and isinstance(aws_event["headers"], dict):
|
|
507
|
+
headers = aws_event["headers"]
|
|
508
|
+
|
|
509
|
+
if headers.get("X-Forwarded-Proto"):
|
|
510
|
+
attributes["network.protocol.name"] = headers["X-Forwarded-Proto"]
|
|
511
|
+
if headers.get("Host"):
|
|
512
|
+
attributes["server.address"] = headers["Host"]
|
|
513
|
+
|
|
514
|
+
attributes.update(_request_headers_to_span_attributes(headers))
|
|
515
|
+
|
|
516
|
+
return attributes
|
sentry_sdk/integrations/boto3.py
CHANGED
|
@@ -3,7 +3,6 @@ from functools import partial
|
|
|
3
3
|
import sentry_sdk
|
|
4
4
|
from sentry_sdk.consts import OP, SPANDATA
|
|
5
5
|
from sentry_sdk.integrations import _check_minimum_version, Integration, DidNotEnable
|
|
6
|
-
from sentry_sdk.tracing import Span
|
|
7
6
|
from sentry_sdk.utils import (
|
|
8
7
|
capture_internal_exceptions,
|
|
9
8
|
ensure_integration_enabled,
|
|
@@ -19,6 +18,8 @@ if TYPE_CHECKING:
|
|
|
19
18
|
from typing import Optional
|
|
20
19
|
from typing import Type
|
|
21
20
|
|
|
21
|
+
from sentry_sdk.tracing import Span
|
|
22
|
+
|
|
22
23
|
try:
|
|
23
24
|
from botocore import __version__ as BOTOCORE_VERSION # type: ignore
|
|
24
25
|
from botocore.client import BaseClient # type: ignore
|
|
@@ -63,17 +64,23 @@ def _sentry_request_created(service_id, request, operation_name, **kwargs):
|
|
|
63
64
|
op=OP.HTTP_CLIENT,
|
|
64
65
|
name=description,
|
|
65
66
|
origin=Boto3Integration.origin,
|
|
67
|
+
only_if_parent=True,
|
|
66
68
|
)
|
|
67
69
|
|
|
70
|
+
data = {
|
|
71
|
+
SPANDATA.HTTP_METHOD: request.method,
|
|
72
|
+
}
|
|
68
73
|
with capture_internal_exceptions():
|
|
69
74
|
parsed_url = parse_url(request.url, sanitize=False)
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
75
|
+
data["aws.request.url"] = parsed_url.url
|
|
76
|
+
data[SPANDATA.HTTP_QUERY] = parsed_url.query
|
|
77
|
+
data[SPANDATA.HTTP_FRAGMENT] = parsed_url.fragment
|
|
78
|
+
|
|
79
|
+
for key, value in data.items():
|
|
80
|
+
span.set_attribute(key, value)
|
|
73
81
|
|
|
74
82
|
span.set_tag("aws.service_id", service_id)
|
|
75
83
|
span.set_tag("aws.operation_name", operation_name)
|
|
76
|
-
span.set_data(SPANDATA.HTTP_METHOD, request.method)
|
|
77
84
|
|
|
78
85
|
# We do it in order for subsequent http calls/retries be
|
|
79
86
|
# attached to this span.
|
|
@@ -82,6 +89,7 @@ def _sentry_request_created(service_id, request, operation_name, **kwargs):
|
|
|
82
89
|
# request.context is an open-ended data-structure
|
|
83
90
|
# where we can add anything useful in request life cycle.
|
|
84
91
|
request.context["_sentrysdk_span"] = span
|
|
92
|
+
request.context["_sentrysdk_span_data"] = data
|
|
85
93
|
|
|
86
94
|
|
|
87
95
|
def _sentry_after_call(context, parsed, **kwargs):
|
|
@@ -91,20 +99,28 @@ def _sentry_after_call(context, parsed, **kwargs):
|
|
|
91
99
|
# Span could be absent if the integration is disabled.
|
|
92
100
|
if span is None:
|
|
93
101
|
return
|
|
94
|
-
|
|
102
|
+
|
|
103
|
+
span_data = context.pop("_sentrysdk_span_data", {})
|
|
104
|
+
|
|
105
|
+
sentry_sdk.add_breadcrumb(
|
|
106
|
+
type="http",
|
|
107
|
+
category="httplib",
|
|
108
|
+
data=span_data,
|
|
109
|
+
)
|
|
95
110
|
|
|
96
111
|
body = parsed.get("Body")
|
|
97
112
|
if not isinstance(body, StreamingBody):
|
|
113
|
+
span.__exit__(None, None, None)
|
|
98
114
|
return
|
|
99
115
|
|
|
100
|
-
streaming_span =
|
|
116
|
+
streaming_span = sentry_sdk.start_span(
|
|
101
117
|
op=OP.HTTP_CLIENT_STREAM,
|
|
102
|
-
name=span.
|
|
118
|
+
name=span.name,
|
|
103
119
|
origin=Boto3Integration.origin,
|
|
120
|
+
only_if_parent=True,
|
|
104
121
|
)
|
|
105
122
|
|
|
106
123
|
orig_read = body.read
|
|
107
|
-
orig_close = body.close
|
|
108
124
|
|
|
109
125
|
def sentry_streaming_body_read(*args, **kwargs):
|
|
110
126
|
# type: (*Any, **Any) -> bytes
|
|
@@ -119,6 +135,8 @@ def _sentry_after_call(context, parsed, **kwargs):
|
|
|
119
135
|
|
|
120
136
|
body.read = sentry_streaming_body_read
|
|
121
137
|
|
|
138
|
+
orig_close = body.close
|
|
139
|
+
|
|
122
140
|
def sentry_streaming_body_close(*args, **kwargs):
|
|
123
141
|
# type: (*Any, **Any) -> None
|
|
124
142
|
streaming_span.finish()
|
|
@@ -126,6 +144,8 @@ def _sentry_after_call(context, parsed, **kwargs):
|
|
|
126
144
|
|
|
127
145
|
body.close = sentry_streaming_body_close
|
|
128
146
|
|
|
147
|
+
span.__exit__(None, None, None)
|
|
148
|
+
|
|
129
149
|
|
|
130
150
|
def _sentry_after_call_error(context, exception, **kwargs):
|
|
131
151
|
# type: (Dict[str, Any], Type[BaseException], **Any) -> None
|
|
@@ -134,4 +154,13 @@ def _sentry_after_call_error(context, exception, **kwargs):
|
|
|
134
154
|
# Span could be absent if the integration is disabled.
|
|
135
155
|
if span is None:
|
|
136
156
|
return
|
|
157
|
+
|
|
158
|
+
span_data = context.pop("_sentrysdk_span_data", {})
|
|
159
|
+
|
|
160
|
+
sentry_sdk.add_breadcrumb(
|
|
161
|
+
type="http",
|
|
162
|
+
category="httplib",
|
|
163
|
+
data=span_data,
|
|
164
|
+
)
|
|
165
|
+
|
|
137
166
|
span.__exit__(type(exception), exception, None)
|