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,26 +1,25 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
1
2
|
import urllib
|
|
2
3
|
|
|
3
4
|
from sentry_sdk.scope import should_send_default_pii
|
|
4
5
|
from sentry_sdk.integrations._wsgi_common import _filter_headers
|
|
5
6
|
|
|
6
|
-
from typing import TYPE_CHECKING
|
|
7
|
+
from typing import TYPE_CHECKING
|
|
7
8
|
|
|
8
9
|
if TYPE_CHECKING:
|
|
9
10
|
from typing import Any
|
|
10
11
|
from typing import Dict
|
|
11
12
|
from typing import Optional
|
|
12
13
|
from typing import Union
|
|
13
|
-
from typing_extensions import Literal
|
|
14
14
|
|
|
15
15
|
from sentry_sdk.utils import AnnotatedValue
|
|
16
16
|
|
|
17
17
|
|
|
18
|
-
def _get_headers(asgi_scope):
|
|
19
|
-
# type: (Any) -> Dict[str, str]
|
|
18
|
+
def _get_headers(asgi_scope: Any) -> Dict[str, str]:
|
|
20
19
|
"""
|
|
21
20
|
Extract headers from the ASGI scope, in the format that the Sentry protocol expects.
|
|
22
21
|
"""
|
|
23
|
-
headers
|
|
22
|
+
headers: Dict[str, str] = {}
|
|
24
23
|
for raw_key, raw_value in asgi_scope.get("headers", {}):
|
|
25
24
|
key = raw_key.decode("latin-1")
|
|
26
25
|
value = raw_value.decode("latin-1")
|
|
@@ -32,12 +31,16 @@ def _get_headers(asgi_scope):
|
|
|
32
31
|
return headers
|
|
33
32
|
|
|
34
33
|
|
|
35
|
-
def _get_url(
|
|
36
|
-
|
|
34
|
+
def _get_url(
|
|
35
|
+
asgi_scope: Dict[str, Any],
|
|
36
|
+
host: Optional[Union[AnnotatedValue, str]] = None,
|
|
37
|
+
) -> str:
|
|
37
38
|
"""
|
|
38
39
|
Extract URL from the ASGI scope, without also including the querystring.
|
|
39
40
|
"""
|
|
40
|
-
scheme =
|
|
41
|
+
scheme = asgi_scope.get(
|
|
42
|
+
"scheme", "http" if asgi_scope.get("type") == "http" else "ws"
|
|
43
|
+
)
|
|
41
44
|
server = asgi_scope.get("server", None)
|
|
42
45
|
path = asgi_scope.get("root_path", "") + asgi_scope.get("path", "")
|
|
43
46
|
|
|
@@ -53,8 +56,7 @@ def _get_url(asgi_scope, default_scheme=None, host=None):
|
|
|
53
56
|
return path
|
|
54
57
|
|
|
55
58
|
|
|
56
|
-
def _get_query(asgi_scope):
|
|
57
|
-
# type: (Any) -> Any
|
|
59
|
+
def _get_query(asgi_scope: Any) -> Any:
|
|
58
60
|
"""
|
|
59
61
|
Extract querystring from the ASGI scope, in the format that the Sentry protocol expects.
|
|
60
62
|
"""
|
|
@@ -64,8 +66,7 @@ def _get_query(asgi_scope):
|
|
|
64
66
|
return urllib.parse.unquote(qs.decode("latin-1"))
|
|
65
67
|
|
|
66
68
|
|
|
67
|
-
def _get_ip(asgi_scope):
|
|
68
|
-
# type: (Any) -> str
|
|
69
|
+
def _get_ip(asgi_scope: Any) -> str:
|
|
69
70
|
"""
|
|
70
71
|
Extract IP Address from the ASGI scope based on request headers with fallback to scope client.
|
|
71
72
|
"""
|
|
@@ -83,12 +84,11 @@ def _get_ip(asgi_scope):
|
|
|
83
84
|
return asgi_scope.get("client")[0]
|
|
84
85
|
|
|
85
86
|
|
|
86
|
-
def _get_request_data(asgi_scope):
|
|
87
|
-
# type: (Any) -> Dict[str, Any]
|
|
87
|
+
def _get_request_data(asgi_scope: Any) -> Dict[str, Any]:
|
|
88
88
|
"""
|
|
89
89
|
Returns data related to the HTTP request from the ASGI scope.
|
|
90
90
|
"""
|
|
91
|
-
request_data
|
|
91
|
+
request_data: Dict[str, Any] = {}
|
|
92
92
|
ty = asgi_scope["type"]
|
|
93
93
|
if ty in ("http", "websocket"):
|
|
94
94
|
request_data["method"] = asgi_scope.get("method")
|
|
@@ -96,9 +96,7 @@ def _get_request_data(asgi_scope):
|
|
|
96
96
|
request_data["headers"] = headers = _filter_headers(_get_headers(asgi_scope))
|
|
97
97
|
request_data["query_string"] = _get_query(asgi_scope)
|
|
98
98
|
|
|
99
|
-
request_data["url"] = _get_url(
|
|
100
|
-
asgi_scope, "http" if ty == "http" else "ws", headers.get("host")
|
|
101
|
-
)
|
|
99
|
+
request_data["url"] = _get_url(asgi_scope, headers.get("host"))
|
|
102
100
|
|
|
103
101
|
client = asgi_scope.get("client")
|
|
104
102
|
if client and should_send_default_pii():
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
1
2
|
import json
|
|
2
3
|
from copy import deepcopy
|
|
3
4
|
|
|
@@ -50,8 +51,9 @@ DEFAULT_HTTP_METHODS_TO_CAPTURE = (
|
|
|
50
51
|
)
|
|
51
52
|
|
|
52
53
|
|
|
53
|
-
def request_body_within_bounds(
|
|
54
|
-
|
|
54
|
+
def request_body_within_bounds(
|
|
55
|
+
client: Optional[sentry_sdk.client.BaseClient], content_length: int
|
|
56
|
+
) -> bool:
|
|
55
57
|
if client is None:
|
|
56
58
|
return False
|
|
57
59
|
|
|
@@ -73,17 +75,15 @@ class RequestExtractor:
|
|
|
73
75
|
# it. Only some child classes implement all methods that raise
|
|
74
76
|
# NotImplementedError in this class.
|
|
75
77
|
|
|
76
|
-
def __init__(self, request):
|
|
77
|
-
# type: (Any) -> None
|
|
78
|
+
def __init__(self, request: Any) -> None:
|
|
78
79
|
self.request = request
|
|
79
80
|
|
|
80
|
-
def extract_into_event(self, event):
|
|
81
|
-
# type: (Event) -> None
|
|
81
|
+
def extract_into_event(self, event: Event) -> None:
|
|
82
82
|
client = sentry_sdk.get_client()
|
|
83
83
|
if not client.is_active():
|
|
84
84
|
return
|
|
85
85
|
|
|
86
|
-
data
|
|
86
|
+
data: Optional[Union[AnnotatedValue, Dict[str, Any]]] = None
|
|
87
87
|
|
|
88
88
|
content_length = self.content_length()
|
|
89
89
|
request_info = event.get("request", {})
|
|
@@ -119,27 +119,22 @@ class RequestExtractor:
|
|
|
119
119
|
|
|
120
120
|
event["request"] = deepcopy(request_info)
|
|
121
121
|
|
|
122
|
-
def content_length(self):
|
|
123
|
-
# type: () -> int
|
|
122
|
+
def content_length(self) -> int:
|
|
124
123
|
try:
|
|
125
124
|
return int(self.env().get("CONTENT_LENGTH", 0))
|
|
126
125
|
except ValueError:
|
|
127
126
|
return 0
|
|
128
127
|
|
|
129
|
-
def cookies(self):
|
|
130
|
-
# type: () -> MutableMapping[str, Any]
|
|
128
|
+
def cookies(self) -> MutableMapping[str, Any]:
|
|
131
129
|
raise NotImplementedError()
|
|
132
130
|
|
|
133
|
-
def raw_data(self):
|
|
134
|
-
# type: () -> Optional[Union[str, bytes]]
|
|
131
|
+
def raw_data(self) -> Optional[Union[str, bytes]]:
|
|
135
132
|
raise NotImplementedError()
|
|
136
133
|
|
|
137
|
-
def form(self):
|
|
138
|
-
# type: () -> Optional[Dict[str, Any]]
|
|
134
|
+
def form(self) -> Optional[Dict[str, Any]]:
|
|
139
135
|
raise NotImplementedError()
|
|
140
136
|
|
|
141
|
-
def parsed_body(self):
|
|
142
|
-
# type: () -> Optional[Dict[str, Any]]
|
|
137
|
+
def parsed_body(self) -> Optional[Dict[str, Any]]:
|
|
143
138
|
try:
|
|
144
139
|
form = self.form()
|
|
145
140
|
except Exception:
|
|
@@ -161,12 +156,10 @@ class RequestExtractor:
|
|
|
161
156
|
|
|
162
157
|
return self.json()
|
|
163
158
|
|
|
164
|
-
def is_json(self):
|
|
165
|
-
# type: () -> bool
|
|
159
|
+
def is_json(self) -> bool:
|
|
166
160
|
return _is_json_content_type(self.env().get("CONTENT_TYPE"))
|
|
167
161
|
|
|
168
|
-
def json(self):
|
|
169
|
-
# type: () -> Optional[Any]
|
|
162
|
+
def json(self) -> Optional[Any]:
|
|
170
163
|
try:
|
|
171
164
|
if not self.is_json():
|
|
172
165
|
return None
|
|
@@ -190,21 +183,17 @@ class RequestExtractor:
|
|
|
190
183
|
|
|
191
184
|
return None
|
|
192
185
|
|
|
193
|
-
def files(self):
|
|
194
|
-
# type: () -> Optional[Dict[str, Any]]
|
|
186
|
+
def files(self) -> Optional[Dict[str, Any]]:
|
|
195
187
|
raise NotImplementedError()
|
|
196
188
|
|
|
197
|
-
def size_of_file(self, file):
|
|
198
|
-
# type: (Any) -> int
|
|
189
|
+
def size_of_file(self, file: Any) -> int:
|
|
199
190
|
raise NotImplementedError()
|
|
200
191
|
|
|
201
|
-
def env(self):
|
|
202
|
-
# type: () -> Dict[str, Any]
|
|
192
|
+
def env(self) -> Dict[str, Any]:
|
|
203
193
|
raise NotImplementedError()
|
|
204
194
|
|
|
205
195
|
|
|
206
|
-
def _is_json_content_type(ct):
|
|
207
|
-
# type: (Optional[str]) -> bool
|
|
196
|
+
def _is_json_content_type(ct: Optional[str]) -> bool:
|
|
208
197
|
mt = (ct or "").split(";", 1)[0]
|
|
209
198
|
return (
|
|
210
199
|
mt == "application/json"
|
|
@@ -213,8 +202,9 @@ def _is_json_content_type(ct):
|
|
|
213
202
|
)
|
|
214
203
|
|
|
215
204
|
|
|
216
|
-
def _filter_headers(
|
|
217
|
-
|
|
205
|
+
def _filter_headers(
|
|
206
|
+
headers: Mapping[str, str],
|
|
207
|
+
) -> Mapping[str, Union[AnnotatedValue, str]]:
|
|
218
208
|
if should_send_default_pii():
|
|
219
209
|
return headers
|
|
220
210
|
|
|
@@ -228,8 +218,7 @@ def _filter_headers(headers):
|
|
|
228
218
|
}
|
|
229
219
|
|
|
230
220
|
|
|
231
|
-
def _request_headers_to_span_attributes(headers):
|
|
232
|
-
# type: (dict[str, str]) -> dict[str, str]
|
|
221
|
+
def _request_headers_to_span_attributes(headers: dict[str, str]) -> dict[str, str]:
|
|
233
222
|
attributes = {}
|
|
234
223
|
|
|
235
224
|
headers = _filter_headers(headers)
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
1
2
|
import sys
|
|
2
3
|
import weakref
|
|
3
4
|
from functools import wraps
|
|
@@ -85,11 +86,10 @@ class AioHttpIntegration(Integration):
|
|
|
85
86
|
|
|
86
87
|
def __init__(
|
|
87
88
|
self,
|
|
88
|
-
transaction_style="handler_name",
|
|
89
|
+
transaction_style: str = "handler_name",
|
|
89
90
|
*,
|
|
90
|
-
failed_request_status_codes
|
|
91
|
-
):
|
|
92
|
-
# type: (...) -> None
|
|
91
|
+
failed_request_status_codes: Set[int] = _DEFAULT_FAILED_REQUEST_STATUS_CODES,
|
|
92
|
+
) -> None:
|
|
93
93
|
if transaction_style not in TRANSACTION_STYLE_VALUES:
|
|
94
94
|
raise ValueError(
|
|
95
95
|
"Invalid value for transaction_style: %s (must be in %s)"
|
|
@@ -99,8 +99,7 @@ class AioHttpIntegration(Integration):
|
|
|
99
99
|
self._failed_request_status_codes = failed_request_status_codes
|
|
100
100
|
|
|
101
101
|
@staticmethod
|
|
102
|
-
def setup_once():
|
|
103
|
-
# type: () -> None
|
|
102
|
+
def setup_once() -> None:
|
|
104
103
|
|
|
105
104
|
version = parse_version(AIOHTTP_VERSION)
|
|
106
105
|
_check_minimum_version(AioHttpIntegration, version)
|
|
@@ -117,8 +116,9 @@ class AioHttpIntegration(Integration):
|
|
|
117
116
|
|
|
118
117
|
old_handle = Application._handle
|
|
119
118
|
|
|
120
|
-
async def sentry_app_handle(
|
|
121
|
-
|
|
119
|
+
async def sentry_app_handle(
|
|
120
|
+
self: Any, request: Request, *args: Any, **kwargs: Any
|
|
121
|
+
) -> Any:
|
|
122
122
|
integration = sentry_sdk.get_client().get_integration(AioHttpIntegration)
|
|
123
123
|
if integration is None:
|
|
124
124
|
return await old_handle(self, request, *args, **kwargs)
|
|
@@ -172,8 +172,9 @@ class AioHttpIntegration(Integration):
|
|
|
172
172
|
old_urldispatcher_resolve = UrlDispatcher.resolve
|
|
173
173
|
|
|
174
174
|
@wraps(old_urldispatcher_resolve)
|
|
175
|
-
async def sentry_urldispatcher_resolve(
|
|
176
|
-
|
|
175
|
+
async def sentry_urldispatcher_resolve(
|
|
176
|
+
self: UrlDispatcher, request: Request
|
|
177
|
+
) -> UrlMappingMatchInfo:
|
|
177
178
|
rv = await old_urldispatcher_resolve(self, request)
|
|
178
179
|
|
|
179
180
|
integration = sentry_sdk.get_client().get_integration(AioHttpIntegration)
|
|
@@ -205,8 +206,7 @@ class AioHttpIntegration(Integration):
|
|
|
205
206
|
old_client_session_init = ClientSession.__init__
|
|
206
207
|
|
|
207
208
|
@ensure_integration_enabled(AioHttpIntegration, old_client_session_init)
|
|
208
|
-
def init(*args, **kwargs):
|
|
209
|
-
# type: (Any, Any) -> None
|
|
209
|
+
def init(*args: Any, **kwargs: Any) -> None:
|
|
210
210
|
client_trace_configs = list(kwargs.get("trace_configs") or ())
|
|
211
211
|
trace_config = create_trace_config()
|
|
212
212
|
client_trace_configs.append(trace_config)
|
|
@@ -217,11 +217,13 @@ class AioHttpIntegration(Integration):
|
|
|
217
217
|
ClientSession.__init__ = init
|
|
218
218
|
|
|
219
219
|
|
|
220
|
-
def create_trace_config():
|
|
221
|
-
# type: () -> TraceConfig
|
|
220
|
+
def create_trace_config() -> TraceConfig:
|
|
222
221
|
|
|
223
|
-
async def on_request_start(
|
|
224
|
-
|
|
222
|
+
async def on_request_start(
|
|
223
|
+
session: ClientSession,
|
|
224
|
+
trace_config_ctx: SimpleNamespace,
|
|
225
|
+
params: TraceRequestStartParams,
|
|
226
|
+
) -> None:
|
|
225
227
|
if sentry_sdk.get_client().get_integration(AioHttpIntegration) is None:
|
|
226
228
|
return
|
|
227
229
|
|
|
@@ -236,7 +238,7 @@ def create_trace_config():
|
|
|
236
238
|
name="%s %s"
|
|
237
239
|
% (method, parsed_url.url if parsed_url else SENSITIVE_DATA_SUBSTITUTE),
|
|
238
240
|
origin=AioHttpIntegration.origin,
|
|
239
|
-
|
|
241
|
+
only_as_child_span=True,
|
|
240
242
|
)
|
|
241
243
|
|
|
242
244
|
data = {
|
|
@@ -277,8 +279,11 @@ def create_trace_config():
|
|
|
277
279
|
trace_config_ctx.span = span
|
|
278
280
|
trace_config_ctx.span_data = data
|
|
279
281
|
|
|
280
|
-
async def on_request_end(
|
|
281
|
-
|
|
282
|
+
async def on_request_end(
|
|
283
|
+
session: ClientSession,
|
|
284
|
+
trace_config_ctx: SimpleNamespace,
|
|
285
|
+
params: TraceRequestEndParams,
|
|
286
|
+
) -> None:
|
|
282
287
|
if trace_config_ctx.span is None:
|
|
283
288
|
return
|
|
284
289
|
|
|
@@ -307,13 +312,13 @@ def create_trace_config():
|
|
|
307
312
|
return trace_config
|
|
308
313
|
|
|
309
314
|
|
|
310
|
-
def _make_request_processor(
|
|
311
|
-
|
|
315
|
+
def _make_request_processor(
|
|
316
|
+
weak_request: weakref.ReferenceType[Request],
|
|
317
|
+
) -> EventProcessor:
|
|
312
318
|
def aiohttp_processor(
|
|
313
|
-
event
|
|
314
|
-
hint
|
|
315
|
-
):
|
|
316
|
-
# type: (...) -> Event
|
|
319
|
+
event: Event,
|
|
320
|
+
hint: dict[str, Tuple[type, BaseException, Any]],
|
|
321
|
+
) -> Event:
|
|
317
322
|
request = weak_request()
|
|
318
323
|
if request is None:
|
|
319
324
|
return event
|
|
@@ -342,8 +347,7 @@ def _make_request_processor(weak_request):
|
|
|
342
347
|
return aiohttp_processor
|
|
343
348
|
|
|
344
349
|
|
|
345
|
-
def _capture_exception():
|
|
346
|
-
# type: () -> ExcInfo
|
|
350
|
+
def _capture_exception() -> ExcInfo:
|
|
347
351
|
exc_info = sys.exc_info()
|
|
348
352
|
event, hint = event_from_exception(
|
|
349
353
|
exc_info,
|
|
@@ -357,8 +361,7 @@ def _capture_exception():
|
|
|
357
361
|
BODY_NOT_READ_MESSAGE = "[Can't show request body due to implementation details.]"
|
|
358
362
|
|
|
359
363
|
|
|
360
|
-
def get_aiohttp_request_data(request):
|
|
361
|
-
# type: (Request) -> Union[Optional[str], AnnotatedValue]
|
|
364
|
+
def get_aiohttp_request_data(request: Request) -> Union[Optional[str], AnnotatedValue]:
|
|
362
365
|
bytes_body = request._read_bytes
|
|
363
366
|
|
|
364
367
|
if bytes_body is not None:
|
|
@@ -377,8 +380,7 @@ def get_aiohttp_request_data(request):
|
|
|
377
380
|
return None
|
|
378
381
|
|
|
379
382
|
|
|
380
|
-
def _prepopulate_attributes(request):
|
|
381
|
-
# type: (Request) -> dict[str, Any]
|
|
383
|
+
def _prepopulate_attributes(request: Request) -> dict[str, Any]:
|
|
382
384
|
"""Construct initial span attributes that can be used in traces sampler."""
|
|
383
385
|
attributes = {}
|
|
384
386
|
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
1
2
|
from functools import wraps
|
|
2
3
|
from typing import TYPE_CHECKING
|
|
3
4
|
|
|
@@ -29,13 +30,11 @@ class AnthropicIntegration(Integration):
|
|
|
29
30
|
identifier = "anthropic"
|
|
30
31
|
origin = f"auto.ai.{identifier}"
|
|
31
32
|
|
|
32
|
-
def __init__(self, include_prompts=True):
|
|
33
|
-
# type: (AnthropicIntegration, bool) -> None
|
|
33
|
+
def __init__(self: AnthropicIntegration, include_prompts: bool = True) -> None:
|
|
34
34
|
self.include_prompts = include_prompts
|
|
35
35
|
|
|
36
36
|
@staticmethod
|
|
37
|
-
def setup_once():
|
|
38
|
-
# type: () -> None
|
|
37
|
+
def setup_once() -> None:
|
|
39
38
|
version = package_version("anthropic")
|
|
40
39
|
_check_minimum_version(AnthropicIntegration, version)
|
|
41
40
|
|
|
@@ -43,8 +42,7 @@ class AnthropicIntegration(Integration):
|
|
|
43
42
|
AsyncMessages.create = _wrap_message_create_async(AsyncMessages.create)
|
|
44
43
|
|
|
45
44
|
|
|
46
|
-
def _capture_exception(exc):
|
|
47
|
-
# type: (Any) -> None
|
|
45
|
+
def _capture_exception(exc: Any) -> None:
|
|
48
46
|
event, hint = event_from_exception(
|
|
49
47
|
exc,
|
|
50
48
|
client_options=sentry_sdk.get_client().options,
|
|
@@ -53,8 +51,7 @@ def _capture_exception(exc):
|
|
|
53
51
|
sentry_sdk.capture_event(event, hint=hint)
|
|
54
52
|
|
|
55
53
|
|
|
56
|
-
def _calculate_token_usage(result, span):
|
|
57
|
-
# type: (Messages, Span) -> None
|
|
54
|
+
def _calculate_token_usage(result: Messages, span: Span) -> None:
|
|
58
55
|
input_tokens = 0
|
|
59
56
|
output_tokens = 0
|
|
60
57
|
if hasattr(result, "usage"):
|
|
@@ -65,11 +62,16 @@ def _calculate_token_usage(result, span):
|
|
|
65
62
|
output_tokens = usage.output_tokens
|
|
66
63
|
|
|
67
64
|
total_tokens = input_tokens + output_tokens
|
|
68
|
-
|
|
65
|
+
|
|
66
|
+
record_token_usage(
|
|
67
|
+
span,
|
|
68
|
+
input_tokens=input_tokens,
|
|
69
|
+
output_tokens=output_tokens,
|
|
70
|
+
total_tokens=total_tokens,
|
|
71
|
+
)
|
|
69
72
|
|
|
70
73
|
|
|
71
|
-
def _get_responses(content):
|
|
72
|
-
# type: (list[Any]) -> list[dict[str, Any]]
|
|
74
|
+
def _get_responses(content: list[Any]) -> list[dict[str, Any]]:
|
|
73
75
|
"""
|
|
74
76
|
Get JSON of a Anthropic responses.
|
|
75
77
|
"""
|
|
@@ -85,8 +87,12 @@ def _get_responses(content):
|
|
|
85
87
|
return responses
|
|
86
88
|
|
|
87
89
|
|
|
88
|
-
def _collect_ai_data(
|
|
89
|
-
|
|
90
|
+
def _collect_ai_data(
|
|
91
|
+
event: MessageStreamEvent,
|
|
92
|
+
input_tokens: int,
|
|
93
|
+
output_tokens: int,
|
|
94
|
+
content_blocks: list[str],
|
|
95
|
+
) -> tuple[int, int, list[str]]:
|
|
90
96
|
"""
|
|
91
97
|
Count token usage and collect content blocks from the AI streaming response.
|
|
92
98
|
"""
|
|
@@ -112,9 +118,12 @@ def _collect_ai_data(event, input_tokens, output_tokens, content_blocks):
|
|
|
112
118
|
|
|
113
119
|
|
|
114
120
|
def _add_ai_data_to_span(
|
|
115
|
-
span
|
|
116
|
-
|
|
117
|
-
|
|
121
|
+
span: Span,
|
|
122
|
+
integration: AnthropicIntegration,
|
|
123
|
+
input_tokens: int,
|
|
124
|
+
output_tokens: int,
|
|
125
|
+
content_blocks: list[str],
|
|
126
|
+
) -> None:
|
|
118
127
|
"""
|
|
119
128
|
Add token usage and content blocks from the AI streaming response to the span.
|
|
120
129
|
"""
|
|
@@ -126,12 +135,16 @@ def _add_ai_data_to_span(
|
|
|
126
135
|
[{"type": "text", "text": complete_message}],
|
|
127
136
|
)
|
|
128
137
|
total_tokens = input_tokens + output_tokens
|
|
129
|
-
record_token_usage(
|
|
138
|
+
record_token_usage(
|
|
139
|
+
span,
|
|
140
|
+
input_tokens=input_tokens,
|
|
141
|
+
output_tokens=output_tokens,
|
|
142
|
+
total_tokens=total_tokens,
|
|
143
|
+
)
|
|
130
144
|
span.set_attribute(SPANDATA.AI_STREAMING, True)
|
|
131
145
|
|
|
132
146
|
|
|
133
|
-
def _sentry_patched_create_common(f, *args, **kwargs):
|
|
134
|
-
# type: (Any, *Any, **Any) -> Any
|
|
147
|
+
def _sentry_patched_create_common(f: Any, *args: Any, **kwargs: Any) -> Any:
|
|
135
148
|
integration = kwargs.pop("integration")
|
|
136
149
|
if integration is None:
|
|
137
150
|
return f(*args, **kwargs)
|
|
@@ -148,7 +161,7 @@ def _sentry_patched_create_common(f, *args, **kwargs):
|
|
|
148
161
|
op=OP.ANTHROPIC_MESSAGES_CREATE,
|
|
149
162
|
description="Anthropic messages create",
|
|
150
163
|
origin=AnthropicIntegration.origin,
|
|
151
|
-
|
|
164
|
+
only_as_child_span=True,
|
|
152
165
|
)
|
|
153
166
|
span.__enter__()
|
|
154
167
|
|
|
@@ -177,11 +190,10 @@ def _sentry_patched_create_common(f, *args, **kwargs):
|
|
|
177
190
|
elif hasattr(result, "_iterator"):
|
|
178
191
|
old_iterator = result._iterator
|
|
179
192
|
|
|
180
|
-
def new_iterator():
|
|
181
|
-
# type: () -> Iterator[MessageStreamEvent]
|
|
193
|
+
def new_iterator() -> Iterator[MessageStreamEvent]:
|
|
182
194
|
input_tokens = 0
|
|
183
195
|
output_tokens = 0
|
|
184
|
-
content_blocks
|
|
196
|
+
content_blocks: list[str] = []
|
|
185
197
|
|
|
186
198
|
for event in old_iterator:
|
|
187
199
|
input_tokens, output_tokens, content_blocks = _collect_ai_data(
|
|
@@ -194,11 +206,10 @@ def _sentry_patched_create_common(f, *args, **kwargs):
|
|
|
194
206
|
)
|
|
195
207
|
span.__exit__(None, None, None)
|
|
196
208
|
|
|
197
|
-
async def new_iterator_async():
|
|
198
|
-
# type: () -> AsyncIterator[MessageStreamEvent]
|
|
209
|
+
async def new_iterator_async() -> AsyncIterator[MessageStreamEvent]:
|
|
199
210
|
input_tokens = 0
|
|
200
211
|
output_tokens = 0
|
|
201
|
-
content_blocks
|
|
212
|
+
content_blocks: list[str] = []
|
|
202
213
|
|
|
203
214
|
async for event in old_iterator:
|
|
204
215
|
input_tokens, output_tokens, content_blocks = _collect_ai_data(
|
|
@@ -223,10 +234,8 @@ def _sentry_patched_create_common(f, *args, **kwargs):
|
|
|
223
234
|
return result
|
|
224
235
|
|
|
225
236
|
|
|
226
|
-
def _wrap_message_create(f):
|
|
227
|
-
|
|
228
|
-
def _execute_sync(f, *args, **kwargs):
|
|
229
|
-
# type: (Any, *Any, **Any) -> Any
|
|
237
|
+
def _wrap_message_create(f: Any) -> Any:
|
|
238
|
+
def _execute_sync(f: Any, *args: Any, **kwargs: Any) -> Any:
|
|
230
239
|
gen = _sentry_patched_create_common(f, *args, **kwargs)
|
|
231
240
|
|
|
232
241
|
try:
|
|
@@ -246,8 +255,7 @@ def _wrap_message_create(f):
|
|
|
246
255
|
return e.value
|
|
247
256
|
|
|
248
257
|
@wraps(f)
|
|
249
|
-
def _sentry_patched_create_sync(*args, **kwargs):
|
|
250
|
-
# type: (*Any, **Any) -> Any
|
|
258
|
+
def _sentry_patched_create_sync(*args: Any, **kwargs: Any) -> Any:
|
|
251
259
|
integration = sentry_sdk.get_client().get_integration(AnthropicIntegration)
|
|
252
260
|
kwargs["integration"] = integration
|
|
253
261
|
|
|
@@ -256,10 +264,8 @@ def _wrap_message_create(f):
|
|
|
256
264
|
return _sentry_patched_create_sync
|
|
257
265
|
|
|
258
266
|
|
|
259
|
-
def _wrap_message_create_async(f):
|
|
260
|
-
|
|
261
|
-
async def _execute_async(f, *args, **kwargs):
|
|
262
|
-
# type: (Any, *Any, **Any) -> Any
|
|
267
|
+
def _wrap_message_create_async(f: Any) -> Any:
|
|
268
|
+
async def _execute_async(f: Any, *args: Any, **kwargs: Any) -> Any:
|
|
263
269
|
gen = _sentry_patched_create_common(f, *args, **kwargs)
|
|
264
270
|
|
|
265
271
|
try:
|
|
@@ -279,8 +285,7 @@ def _wrap_message_create_async(f):
|
|
|
279
285
|
return e.value
|
|
280
286
|
|
|
281
287
|
@wraps(f)
|
|
282
|
-
async def _sentry_patched_create_async(*args, **kwargs):
|
|
283
|
-
# type: (*Any, **Any) -> Any
|
|
288
|
+
async def _sentry_patched_create_async(*args: Any, **kwargs: Any) -> Any:
|
|
284
289
|
integration = sentry_sdk.get_client().get_integration(AnthropicIntegration)
|
|
285
290
|
kwargs["integration"] = integration
|
|
286
291
|
|
sentry_sdk/integrations/argv.py
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
1
2
|
import sys
|
|
2
3
|
|
|
3
4
|
import sentry_sdk
|
|
@@ -16,11 +17,9 @@ class ArgvIntegration(Integration):
|
|
|
16
17
|
identifier = "argv"
|
|
17
18
|
|
|
18
19
|
@staticmethod
|
|
19
|
-
def setup_once():
|
|
20
|
-
# type: () -> None
|
|
20
|
+
def setup_once() -> None:
|
|
21
21
|
@add_global_event_processor
|
|
22
|
-
def processor(event, hint):
|
|
23
|
-
# type: (Event, Optional[Hint]) -> Optional[Event]
|
|
22
|
+
def processor(event: Event, hint: Optional[Hint]) -> Optional[Event]:
|
|
24
23
|
if sentry_sdk.get_client().get_integration(ArgvIntegration) is not None:
|
|
25
24
|
extra = event.setdefault("extra", {})
|
|
26
25
|
# If some event processor decided to set extra to e.g. an
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
1
2
|
from importlib import import_module
|
|
2
3
|
|
|
3
4
|
import sentry_sdk
|
|
@@ -33,8 +34,7 @@ class AriadneIntegration(Integration):
|
|
|
33
34
|
identifier = "ariadne"
|
|
34
35
|
|
|
35
36
|
@staticmethod
|
|
36
|
-
def setup_once():
|
|
37
|
-
# type: () -> None
|
|
37
|
+
def setup_once() -> None:
|
|
38
38
|
version = package_version("ariadne")
|
|
39
39
|
_check_minimum_version(AriadneIntegration, version)
|
|
40
40
|
|
|
@@ -43,15 +43,15 @@ class AriadneIntegration(Integration):
|
|
|
43
43
|
_patch_graphql()
|
|
44
44
|
|
|
45
45
|
|
|
46
|
-
def _patch_graphql():
|
|
47
|
-
# type: () -> None
|
|
46
|
+
def _patch_graphql() -> None:
|
|
48
47
|
old_parse_query = ariadne_graphql.parse_query
|
|
49
48
|
old_handle_errors = ariadne_graphql.handle_graphql_errors
|
|
50
49
|
old_handle_query_result = ariadne_graphql.handle_query_result
|
|
51
50
|
|
|
52
51
|
@ensure_integration_enabled(AriadneIntegration, old_parse_query)
|
|
53
|
-
def _sentry_patched_parse_query(
|
|
54
|
-
|
|
52
|
+
def _sentry_patched_parse_query(
|
|
53
|
+
context_value: Optional[Any], query_parser: Optional[QueryParser], data: Any
|
|
54
|
+
) -> DocumentNode:
|
|
55
55
|
event_processor = _make_request_event_processor(data)
|
|
56
56
|
sentry_sdk.get_isolation_scope().add_event_processor(event_processor)
|
|
57
57
|
|
|
@@ -59,8 +59,9 @@ def _patch_graphql():
|
|
|
59
59
|
return result
|
|
60
60
|
|
|
61
61
|
@ensure_integration_enabled(AriadneIntegration, old_handle_errors)
|
|
62
|
-
def _sentry_patched_handle_graphql_errors(
|
|
63
|
-
|
|
62
|
+
def _sentry_patched_handle_graphql_errors(
|
|
63
|
+
errors: List[GraphQLError], *args: Any, **kwargs: Any
|
|
64
|
+
) -> GraphQLResult:
|
|
64
65
|
result = old_handle_errors(errors, *args, **kwargs)
|
|
65
66
|
|
|
66
67
|
event_processor = _make_response_event_processor(result[1])
|
|
@@ -83,8 +84,9 @@ def _patch_graphql():
|
|
|
83
84
|
return result
|
|
84
85
|
|
|
85
86
|
@ensure_integration_enabled(AriadneIntegration, old_handle_query_result)
|
|
86
|
-
def _sentry_patched_handle_query_result(
|
|
87
|
-
|
|
87
|
+
def _sentry_patched_handle_query_result(
|
|
88
|
+
result: Any, *args: Any, **kwargs: Any
|
|
89
|
+
) -> GraphQLResult:
|
|
88
90
|
query_result = old_handle_query_result(result, *args, **kwargs)
|
|
89
91
|
|
|
90
92
|
event_processor = _make_response_event_processor(query_result[1])
|
|
@@ -111,12 +113,10 @@ def _patch_graphql():
|
|
|
111
113
|
ariadne_graphql.handle_query_result = _sentry_patched_handle_query_result # type: ignore
|
|
112
114
|
|
|
113
115
|
|
|
114
|
-
def _make_request_event_processor(data):
|
|
115
|
-
# type: (GraphQLSchema) -> EventProcessor
|
|
116
|
+
def _make_request_event_processor(data: GraphQLSchema) -> EventProcessor:
|
|
116
117
|
"""Add request data and api_target to events."""
|
|
117
118
|
|
|
118
|
-
def inner(event, hint):
|
|
119
|
-
# type: (Event, dict[str, Any]) -> Event
|
|
119
|
+
def inner(event: Event, hint: dict[str, Any]) -> Event:
|
|
120
120
|
if not isinstance(data, dict):
|
|
121
121
|
return event
|
|
122
122
|
|
|
@@ -143,12 +143,10 @@ def _make_request_event_processor(data):
|
|
|
143
143
|
return inner
|
|
144
144
|
|
|
145
145
|
|
|
146
|
-
def _make_response_event_processor(response):
|
|
147
|
-
# type: (Dict[str, Any]) -> EventProcessor
|
|
146
|
+
def _make_response_event_processor(response: Dict[str, Any]) -> EventProcessor:
|
|
148
147
|
"""Add response data to the event's response context."""
|
|
149
148
|
|
|
150
|
-
def inner(event, hint):
|
|
151
|
-
# type: (Event, dict[str, Any]) -> Event
|
|
149
|
+
def inner(event: Event, hint: dict[str, Any]) -> Event:
|
|
152
150
|
with capture_internal_exceptions():
|
|
153
151
|
if should_send_default_pii() and response.get("errors"):
|
|
154
152
|
contexts = event.setdefault("contexts", {})
|