sentry-sdk 3.0.0a1__py2.py3-none-any.whl → 3.0.0a3__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 +2 -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 +11 -18
- sentry_sdk/_werkzeug.py +5 -7
- sentry_sdk/ai/monitoring.py +44 -31
- sentry_sdk/ai/utils.py +3 -4
- sentry_sdk/api.py +75 -87
- sentry_sdk/attachments.py +10 -12
- sentry_sdk/client.py +137 -155
- sentry_sdk/consts.py +430 -174
- 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 +15 -18
- sentry_sdk/integrations/_wsgi_common.py +22 -33
- sentry_sdk/integrations/aiohttp.py +32 -30
- sentry_sdk/integrations/anthropic.py +42 -37
- sentry_sdk/integrations/argv.py +3 -4
- sentry_sdk/integrations/ariadne.py +16 -18
- sentry_sdk/integrations/arq.py +21 -29
- sentry_sdk/integrations/asgi.py +63 -37
- sentry_sdk/integrations/asyncio.py +14 -16
- 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 +18 -16
- sentry_sdk/integrations/bottle.py +25 -34
- sentry_sdk/integrations/celery/__init__.py +41 -61
- sentry_sdk/integrations/celery/beat.py +23 -27
- sentry_sdk/integrations/celery/utils.py +15 -17
- sentry_sdk/integrations/chalice.py +8 -10
- sentry_sdk/integrations/clickhouse_driver.py +21 -31
- sentry_sdk/integrations/cloud_resource_context.py +9 -16
- sentry_sdk/integrations/cohere.py +27 -33
- sentry_sdk/integrations/dedupe.py +5 -8
- sentry_sdk/integrations/django/__init__.py +57 -72
- sentry_sdk/integrations/django/asgi.py +26 -34
- sentry_sdk/integrations/django/caching.py +23 -19
- sentry_sdk/integrations/django/middleware.py +17 -20
- sentry_sdk/integrations/django/signals_handlers.py +11 -10
- sentry_sdk/integrations/django/templates.py +19 -16
- sentry_sdk/integrations/django/transactions.py +16 -11
- sentry_sdk/integrations/django/views.py +6 -10
- 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 +4 -6
- sentry_sdk/integrations/gql.py +16 -17
- sentry_sdk/integrations/graphene.py +13 -12
- sentry_sdk/integrations/grpc/__init__.py +19 -1
- sentry_sdk/integrations/grpc/aio/server.py +15 -14
- sentry_sdk/integrations/grpc/client.py +19 -9
- sentry_sdk/integrations/grpc/consts.py +2 -0
- sentry_sdk/integrations/grpc/server.py +12 -8
- sentry_sdk/integrations/httpx.py +9 -12
- sentry_sdk/integrations/huey.py +13 -20
- sentry_sdk/integrations/huggingface_hub.py +18 -18
- sentry_sdk/integrations/langchain.py +203 -113
- sentry_sdk/integrations/launchdarkly.py +13 -10
- sentry_sdk/integrations/litestar.py +37 -35
- sentry_sdk/integrations/logging.py +52 -65
- sentry_sdk/integrations/loguru.py +127 -57
- sentry_sdk/integrations/modules.py +3 -4
- sentry_sdk/integrations/openai.py +100 -88
- 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 +201 -0
- sentry_sdk/integrations/openfeature.py +11 -6
- sentry_sdk/integrations/pure_eval.py +6 -10
- sentry_sdk/integrations/pymongo.py +13 -17
- 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 +25 -12
- sentry_sdk/integrations/redis/_sync_common.py +19 -13
- 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 +21 -13
- sentry_sdk/integrations/redis/redis_py_cluster_legacy.py +3 -2
- sentry_sdk/integrations/redis/utils.py +23 -24
- sentry_sdk/integrations/rq.py +13 -16
- sentry_sdk/integrations/rust_tracing.py +9 -6
- sentry_sdk/integrations/sanic.py +34 -46
- sentry_sdk/integrations/serverless.py +22 -27
- sentry_sdk/integrations/socket.py +27 -15
- 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 +86 -90
- sentry_sdk/integrations/starlite.py +28 -34
- sentry_sdk/integrations/statsig.py +5 -4
- sentry_sdk/integrations/stdlib.py +28 -24
- sentry_sdk/integrations/strawberry.py +62 -49
- sentry_sdk/integrations/sys_exit.py +7 -11
- sentry_sdk/integrations/threading.py +12 -14
- 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 +41 -10
- sentry_sdk/monitor.py +16 -28
- sentry_sdk/opentelemetry/consts.py +11 -4
- sentry_sdk/opentelemetry/contextvars_context.py +26 -16
- sentry_sdk/opentelemetry/propagator.py +38 -21
- sentry_sdk/opentelemetry/sampler.py +51 -34
- sentry_sdk/opentelemetry/scope.py +36 -37
- sentry_sdk/opentelemetry/span_processor.py +48 -58
- sentry_sdk/opentelemetry/tracing.py +58 -14
- sentry_sdk/opentelemetry/utils.py +186 -194
- 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 -273
- sentry_sdk/scrubber.py +22 -26
- sentry_sdk/serializer.py +40 -54
- sentry_sdk/session.py +44 -61
- sentry_sdk/sessions.py +35 -49
- sentry_sdk/spotlight.py +15 -21
- sentry_sdk/tracing.py +121 -187
- sentry_sdk/tracing_utils.py +104 -122
- sentry_sdk/transport.py +131 -157
- sentry_sdk/utils.py +232 -309
- sentry_sdk/worker.py +16 -28
- {sentry_sdk-3.0.0a1.dist-info → sentry_sdk-3.0.0a3.dist-info}/METADATA +3 -3
- sentry_sdk-3.0.0a3.dist-info/RECORD +168 -0
- {sentry_sdk-3.0.0a1.dist-info → sentry_sdk-3.0.0a3.dist-info}/WHEEL +1 -1
- sentry_sdk-3.0.0a1.dist-info/RECORD +0 -154
- {sentry_sdk-3.0.0a1.dist-info → sentry_sdk-3.0.0a3.dist-info}/entry_points.txt +0 -0
- {sentry_sdk-3.0.0a1.dist-info → sentry_sdk-3.0.0a3.dist-info}/licenses/LICENSE +0 -0
- {sentry_sdk-3.0.0a1.dist-info → sentry_sdk-3.0.0a3.dist-info}/top_level.txt +0 -0
sentry_sdk/client.py
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
1
2
|
import os
|
|
2
3
|
import uuid
|
|
3
4
|
import random
|
|
@@ -5,8 +6,9 @@ import socket
|
|
|
5
6
|
from collections.abc import Mapping
|
|
6
7
|
from datetime import datetime, timezone
|
|
7
8
|
from importlib import import_module
|
|
8
|
-
from typing import TYPE_CHECKING,
|
|
9
|
+
from typing import TYPE_CHECKING, overload
|
|
9
10
|
|
|
11
|
+
import sentry_sdk
|
|
10
12
|
from sentry_sdk._compat import check_uwsgi_thread_support
|
|
11
13
|
from sentry_sdk.utils import (
|
|
12
14
|
AnnotatedValue,
|
|
@@ -47,13 +49,16 @@ from sentry_sdk.monitor import Monitor
|
|
|
47
49
|
from sentry_sdk.spotlight import setup_spotlight
|
|
48
50
|
|
|
49
51
|
if TYPE_CHECKING:
|
|
50
|
-
from typing import
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
52
|
+
from typing import (
|
|
53
|
+
Any,
|
|
54
|
+
Callable,
|
|
55
|
+
Optional,
|
|
56
|
+
Sequence,
|
|
57
|
+
Type,
|
|
58
|
+
Union,
|
|
59
|
+
TypeVar,
|
|
60
|
+
Dict,
|
|
61
|
+
)
|
|
57
62
|
|
|
58
63
|
from sentry_sdk._types import Event, Hint, SDKInfo, Log
|
|
59
64
|
from sentry_sdk.integrations import Integration
|
|
@@ -63,22 +68,22 @@ if TYPE_CHECKING:
|
|
|
63
68
|
from sentry_sdk.transport import Transport
|
|
64
69
|
from sentry_sdk._log_batcher import LogBatcher
|
|
65
70
|
|
|
66
|
-
|
|
71
|
+
IntegrationType = TypeVar("IntegrationType", bound=Integration) # noqa: E741
|
|
72
|
+
|
|
67
73
|
|
|
68
74
|
_client_init_debug = ContextVar("client_init_debug")
|
|
69
75
|
|
|
70
76
|
|
|
71
|
-
SDK_INFO = {
|
|
77
|
+
SDK_INFO: SDKInfo = {
|
|
72
78
|
"name": "sentry.python", # SDK name will be overridden after integrations have been loaded with sentry_sdk.integrations.setup_integrations()
|
|
73
79
|
"version": VERSION,
|
|
74
80
|
"packages": [{"name": "pypi:sentry-sdk", "version": VERSION}],
|
|
75
|
-
}
|
|
81
|
+
}
|
|
76
82
|
|
|
77
83
|
|
|
78
|
-
def _get_options(*args, **kwargs):
|
|
79
|
-
# type: (*Optional[str], **Any) -> Dict[str, Any]
|
|
84
|
+
def _get_options(*args: Optional[str], **kwargs: Any) -> Dict[str, Any]:
|
|
80
85
|
if args and (isinstance(args[0], (bytes, str)) or args[0] is None):
|
|
81
|
-
dsn = args[0]
|
|
86
|
+
dsn: Optional[str] = args[0]
|
|
82
87
|
args = args[1:]
|
|
83
88
|
else:
|
|
84
89
|
dsn = None
|
|
@@ -107,7 +112,7 @@ def _get_options(*args, **kwargs):
|
|
|
107
112
|
rv["environment"] = os.environ.get("SENTRY_ENVIRONMENT") or "production"
|
|
108
113
|
|
|
109
114
|
if rv["debug"] is None:
|
|
110
|
-
rv["debug"] = env_to_bool(os.environ.get("SENTRY_DEBUG"
|
|
115
|
+
rv["debug"] = env_to_bool(os.environ.get("SENTRY_DEBUG"), strict=True) or False
|
|
111
116
|
|
|
112
117
|
if rv["server_name"] is None and hasattr(socket, "gethostname"):
|
|
113
118
|
rv["server_name"] = socket.gethostname()
|
|
@@ -133,6 +138,11 @@ def _get_options(*args, **kwargs):
|
|
|
133
138
|
)
|
|
134
139
|
rv["socket_options"] = None
|
|
135
140
|
|
|
141
|
+
if rv["keep_alive"] is None:
|
|
142
|
+
rv["keep_alive"] = (
|
|
143
|
+
env_to_bool(os.environ.get("SENTRY_KEEP_ALIVE"), strict=True) or False
|
|
144
|
+
)
|
|
145
|
+
|
|
136
146
|
return rv
|
|
137
147
|
|
|
138
148
|
|
|
@@ -143,37 +153,31 @@ class BaseClient:
|
|
|
143
153
|
The basic definition of a client that is used for sending data to Sentry.
|
|
144
154
|
"""
|
|
145
155
|
|
|
146
|
-
spotlight
|
|
156
|
+
spotlight: Optional[SpotlightClient] = None
|
|
147
157
|
|
|
148
|
-
def __init__(self, options=None):
|
|
149
|
-
|
|
150
|
-
self.options = (
|
|
158
|
+
def __init__(self, options: Optional[Dict[str, Any]] = None) -> None:
|
|
159
|
+
self.options: Dict[str, Any] = (
|
|
151
160
|
options if options is not None else DEFAULT_OPTIONS
|
|
152
|
-
)
|
|
161
|
+
)
|
|
153
162
|
|
|
154
|
-
self.transport
|
|
155
|
-
self.monitor
|
|
156
|
-
self.log_batcher
|
|
163
|
+
self.transport: Optional[Transport] = None
|
|
164
|
+
self.monitor: Optional[Monitor] = None
|
|
165
|
+
self.log_batcher: Optional[LogBatcher] = None
|
|
157
166
|
|
|
158
|
-
def __getstate__(self, *args, **kwargs):
|
|
159
|
-
# type: (*Any, **Any) -> Any
|
|
167
|
+
def __getstate__(self, *args: Any, **kwargs: Any) -> Any:
|
|
160
168
|
return {"options": {}}
|
|
161
169
|
|
|
162
|
-
def __setstate__(self, *args, **kwargs):
|
|
163
|
-
# type: (*Any, **Any) -> None
|
|
170
|
+
def __setstate__(self, *args: Any, **kwargs: Any) -> None:
|
|
164
171
|
pass
|
|
165
172
|
|
|
166
173
|
@property
|
|
167
|
-
def dsn(self):
|
|
168
|
-
# type: () -> Optional[str]
|
|
174
|
+
def dsn(self) -> Optional[str]:
|
|
169
175
|
return None
|
|
170
176
|
|
|
171
|
-
def should_send_default_pii(self):
|
|
172
|
-
# type: () -> bool
|
|
177
|
+
def should_send_default_pii(self) -> bool:
|
|
173
178
|
return False
|
|
174
179
|
|
|
175
|
-
def is_active(self):
|
|
176
|
-
# type: () -> bool
|
|
180
|
+
def is_active(self) -> bool:
|
|
177
181
|
"""
|
|
178
182
|
.. versionadded:: 2.0.0
|
|
179
183
|
|
|
@@ -181,48 +185,40 @@ class BaseClient:
|
|
|
181
185
|
"""
|
|
182
186
|
return False
|
|
183
187
|
|
|
184
|
-
def capture_event(self, *args, **kwargs):
|
|
185
|
-
# type: (*Any, **Any) -> Optional[str]
|
|
188
|
+
def capture_event(self, *args: Any, **kwargs: Any) -> Optional[str]:
|
|
186
189
|
return None
|
|
187
190
|
|
|
188
|
-
def _capture_experimental_log(self,
|
|
189
|
-
# type: (Scope, Log) -> None
|
|
191
|
+
def _capture_experimental_log(self, log: "Log") -> None:
|
|
190
192
|
pass
|
|
191
193
|
|
|
192
|
-
def capture_session(self, *args, **kwargs):
|
|
193
|
-
# type: (*Any, **Any) -> None
|
|
194
|
+
def capture_session(self, *args: Any, **kwargs: Any) -> None:
|
|
194
195
|
return None
|
|
195
196
|
|
|
196
197
|
if TYPE_CHECKING:
|
|
197
198
|
|
|
198
199
|
@overload
|
|
199
|
-
def get_integration(self, name_or_class):
|
|
200
|
-
# type: (str) -> Optional[Integration]
|
|
201
|
-
...
|
|
200
|
+
def get_integration(self, name_or_class: str) -> Optional[Integration]: ...
|
|
202
201
|
|
|
203
202
|
@overload
|
|
204
|
-
def get_integration(
|
|
205
|
-
|
|
206
|
-
|
|
203
|
+
def get_integration(
|
|
204
|
+
self, name_or_class: type[IntegrationType]
|
|
205
|
+
) -> Optional[IntegrationType]: ...
|
|
207
206
|
|
|
208
|
-
def get_integration(
|
|
209
|
-
|
|
207
|
+
def get_integration(
|
|
208
|
+
self, name_or_class: Union[str, type[Integration]]
|
|
209
|
+
) -> Optional[Integration]:
|
|
210
210
|
return None
|
|
211
211
|
|
|
212
|
-
def close(self, *args, **kwargs):
|
|
213
|
-
# type: (*Any, **Any) -> None
|
|
212
|
+
def close(self, *args: Any, **kwargs: Any) -> None:
|
|
214
213
|
return None
|
|
215
214
|
|
|
216
|
-
def flush(self, *args, **kwargs):
|
|
217
|
-
# type: (*Any, **Any) -> None
|
|
215
|
+
def flush(self, *args: Any, **kwargs: Any) -> None:
|
|
218
216
|
return None
|
|
219
217
|
|
|
220
|
-
def __enter__(self):
|
|
221
|
-
# type: () -> BaseClient
|
|
218
|
+
def __enter__(self) -> BaseClient:
|
|
222
219
|
return self
|
|
223
220
|
|
|
224
|
-
def __exit__(self, exc_type, exc_value, tb):
|
|
225
|
-
# type: (Any, Any, Any) -> None
|
|
221
|
+
def __exit__(self, exc_type: Any, exc_value: Any, tb: Any) -> None:
|
|
226
222
|
return None
|
|
227
223
|
|
|
228
224
|
|
|
@@ -246,22 +242,20 @@ class _Client(BaseClient):
|
|
|
246
242
|
Alias of :py:class:`sentry_sdk.Client`. (Was created for better intelisense support)
|
|
247
243
|
"""
|
|
248
244
|
|
|
249
|
-
def __init__(self, *args, **kwargs):
|
|
250
|
-
|
|
251
|
-
super(_Client, self).__init__(options=get_options(*args, **kwargs))
|
|
245
|
+
def __init__(self, *args: Any, **kwargs: Any) -> None:
|
|
246
|
+
super(_Client, self).__init__(options=_get_options(*args, **kwargs))
|
|
252
247
|
self._init_impl()
|
|
253
248
|
|
|
254
|
-
def __getstate__(self):
|
|
255
|
-
# type: () -> Any
|
|
249
|
+
def __getstate__(self) -> Any:
|
|
256
250
|
return {"options": self.options}
|
|
257
251
|
|
|
258
|
-
def __setstate__(self, state):
|
|
259
|
-
# type: (Any) -> None
|
|
252
|
+
def __setstate__(self, state: Any) -> None:
|
|
260
253
|
self.options = state["options"]
|
|
261
254
|
self._init_impl()
|
|
262
255
|
|
|
263
|
-
def _setup_instrumentation(
|
|
264
|
-
|
|
256
|
+
def _setup_instrumentation(
|
|
257
|
+
self, functions_to_trace: Sequence[Dict[str, str]]
|
|
258
|
+
) -> None:
|
|
265
259
|
"""
|
|
266
260
|
Instruments the functions given in the list `functions_to_trace` with the `@sentry_sdk.tracing.trace` decorator.
|
|
267
261
|
"""
|
|
@@ -311,12 +305,10 @@ class _Client(BaseClient):
|
|
|
311
305
|
e,
|
|
312
306
|
)
|
|
313
307
|
|
|
314
|
-
def _init_impl(self):
|
|
315
|
-
# type: () -> None
|
|
308
|
+
def _init_impl(self) -> None:
|
|
316
309
|
old_debug = _client_init_debug.get(False)
|
|
317
310
|
|
|
318
|
-
def _capture_envelope(envelope):
|
|
319
|
-
# type: (Envelope) -> None
|
|
311
|
+
def _capture_envelope(envelope: Envelope) -> None:
|
|
320
312
|
if self.transport is not None:
|
|
321
313
|
self.transport.capture_envelope(envelope)
|
|
322
314
|
|
|
@@ -400,6 +392,8 @@ class _Client(BaseClient):
|
|
|
400
392
|
|
|
401
393
|
patch_readable_span()
|
|
402
394
|
setup_sentry_tracing()
|
|
395
|
+
|
|
396
|
+
logger.debug("[Tracing] Finished setting up OpenTelemetry")
|
|
403
397
|
finally:
|
|
404
398
|
_client_init_debug.set(old_debug)
|
|
405
399
|
|
|
@@ -415,8 +409,7 @@ class _Client(BaseClient):
|
|
|
415
409
|
# need to check if it's safe to use them.
|
|
416
410
|
check_uwsgi_thread_support()
|
|
417
411
|
|
|
418
|
-
def is_active(self):
|
|
419
|
-
# type: () -> bool
|
|
412
|
+
def is_active(self) -> bool:
|
|
420
413
|
"""
|
|
421
414
|
.. versionadded:: 2.0.0
|
|
422
415
|
|
|
@@ -424,8 +417,7 @@ class _Client(BaseClient):
|
|
|
424
417
|
"""
|
|
425
418
|
return True
|
|
426
419
|
|
|
427
|
-
def should_send_default_pii(self):
|
|
428
|
-
# type: () -> bool
|
|
420
|
+
def should_send_default_pii(self) -> bool:
|
|
429
421
|
"""
|
|
430
422
|
.. versionadded:: 2.0.0
|
|
431
423
|
|
|
@@ -434,28 +426,26 @@ class _Client(BaseClient):
|
|
|
434
426
|
return self.options.get("send_default_pii") or False
|
|
435
427
|
|
|
436
428
|
@property
|
|
437
|
-
def dsn(self):
|
|
438
|
-
# type: () -> Optional[str]
|
|
429
|
+
def dsn(self) -> Optional[str]:
|
|
439
430
|
"""Returns the configured DSN as string."""
|
|
440
431
|
return self.options["dsn"]
|
|
441
432
|
|
|
442
433
|
def _prepare_event(
|
|
443
434
|
self,
|
|
444
|
-
event
|
|
445
|
-
hint
|
|
446
|
-
scope
|
|
447
|
-
):
|
|
448
|
-
# type: (...) -> Optional[Event]
|
|
435
|
+
event: Event,
|
|
436
|
+
hint: Hint,
|
|
437
|
+
scope: Optional[Scope],
|
|
438
|
+
) -> Optional[Event]:
|
|
449
439
|
|
|
450
|
-
previous_total_spans
|
|
451
|
-
previous_total_breadcrumbs
|
|
440
|
+
previous_total_spans: Optional[int] = None
|
|
441
|
+
previous_total_breadcrumbs: Optional[int] = None
|
|
452
442
|
|
|
453
443
|
if event.get("timestamp") is None:
|
|
454
444
|
event["timestamp"] = datetime.now(timezone.utc)
|
|
455
445
|
|
|
456
446
|
if scope is not None:
|
|
457
447
|
is_transaction = event.get("type") == "transaction"
|
|
458
|
-
spans_before = len(
|
|
448
|
+
spans_before = len(event.get("spans", []))
|
|
459
449
|
event_ = scope.apply_to_event(event, hint, self.options)
|
|
460
450
|
|
|
461
451
|
# one of the event/error processors returned None
|
|
@@ -473,16 +463,14 @@ class _Client(BaseClient):
|
|
|
473
463
|
)
|
|
474
464
|
return None
|
|
475
465
|
|
|
476
|
-
event = event_
|
|
477
|
-
spans_delta = spans_before - len(
|
|
478
|
-
cast(List[Dict[str, object]], event.get("spans", []))
|
|
479
|
-
)
|
|
466
|
+
event = event_
|
|
467
|
+
spans_delta = spans_before - len(event.get("spans", []))
|
|
480
468
|
if is_transaction and spans_delta > 0 and self.transport is not None:
|
|
481
469
|
self.transport.record_lost_event(
|
|
482
470
|
"event_processor", data_category="span", quantity=spans_delta
|
|
483
471
|
)
|
|
484
472
|
|
|
485
|
-
dropped_spans = event.pop("_dropped_spans", 0) + spans_delta
|
|
473
|
+
dropped_spans: int = event.pop("_dropped_spans", 0) + spans_delta
|
|
486
474
|
if dropped_spans > 0:
|
|
487
475
|
previous_total_spans = spans_before + dropped_spans
|
|
488
476
|
if scope._n_breadcrumbs_truncated > 0:
|
|
@@ -554,14 +542,11 @@ class _Client(BaseClient):
|
|
|
554
542
|
# Postprocess the event here so that annotated types do
|
|
555
543
|
# generally not surface in before_send
|
|
556
544
|
if event is not None:
|
|
557
|
-
event =
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
max_value_length=self.options.get("max_value_length"),
|
|
563
|
-
custom_repr=self.options.get("custom_repr"),
|
|
564
|
-
),
|
|
545
|
+
event: Event = serialize( # type: ignore[no-redef]
|
|
546
|
+
event,
|
|
547
|
+
max_request_body_size=self.options.get("max_request_body_size"),
|
|
548
|
+
max_value_length=self.options.get("max_value_length"),
|
|
549
|
+
custom_repr=self.options.get("custom_repr"),
|
|
565
550
|
)
|
|
566
551
|
|
|
567
552
|
before_send = self.options["before_send"]
|
|
@@ -570,7 +555,7 @@ class _Client(BaseClient):
|
|
|
570
555
|
and event is not None
|
|
571
556
|
and event.get("type") != "transaction"
|
|
572
557
|
):
|
|
573
|
-
new_event
|
|
558
|
+
new_event: Optional["Event"] = None
|
|
574
559
|
with capture_internal_exceptions():
|
|
575
560
|
new_event = before_send(event, hint or {})
|
|
576
561
|
if new_event is None:
|
|
@@ -587,7 +572,7 @@ class _Client(BaseClient):
|
|
|
587
572
|
if event.get("exception"):
|
|
588
573
|
DedupeIntegration.reset_last_seen()
|
|
589
574
|
|
|
590
|
-
event = new_event
|
|
575
|
+
event = new_event
|
|
591
576
|
|
|
592
577
|
before_send_transaction = self.options["before_send_transaction"]
|
|
593
578
|
if (
|
|
@@ -596,7 +581,7 @@ class _Client(BaseClient):
|
|
|
596
581
|
and event.get("type") == "transaction"
|
|
597
582
|
):
|
|
598
583
|
new_event = None
|
|
599
|
-
spans_before = len(
|
|
584
|
+
spans_before = len(event.get("spans", []))
|
|
600
585
|
with capture_internal_exceptions():
|
|
601
586
|
new_event = before_send_transaction(event, hint or {})
|
|
602
587
|
if new_event is None:
|
|
@@ -611,20 +596,17 @@ class _Client(BaseClient):
|
|
|
611
596
|
quantity=spans_before + 1, # +1 for the transaction itself
|
|
612
597
|
)
|
|
613
598
|
else:
|
|
614
|
-
spans_delta = spans_before - len(
|
|
615
|
-
cast(List[Dict[str, object]], new_event.get("spans", []))
|
|
616
|
-
)
|
|
599
|
+
spans_delta = spans_before - len(new_event.get("spans", []))
|
|
617
600
|
if spans_delta > 0 and self.transport is not None:
|
|
618
601
|
self.transport.record_lost_event(
|
|
619
602
|
reason="before_send", data_category="span", quantity=spans_delta
|
|
620
603
|
)
|
|
621
604
|
|
|
622
|
-
event = new_event
|
|
605
|
+
event = new_event
|
|
623
606
|
|
|
624
607
|
return event
|
|
625
608
|
|
|
626
|
-
def _is_ignored_error(self, event, hint):
|
|
627
|
-
# type: (Event, Hint) -> bool
|
|
609
|
+
def _is_ignored_error(self, event: Event, hint: Hint) -> bool:
|
|
628
610
|
exc_info = hint.get("exc_info")
|
|
629
611
|
if exc_info is None:
|
|
630
612
|
return False
|
|
@@ -647,11 +629,10 @@ class _Client(BaseClient):
|
|
|
647
629
|
|
|
648
630
|
def _should_capture(
|
|
649
631
|
self,
|
|
650
|
-
event
|
|
651
|
-
hint
|
|
652
|
-
scope
|
|
653
|
-
):
|
|
654
|
-
# type: (...) -> bool
|
|
632
|
+
event: "Event",
|
|
633
|
+
hint: "Hint",
|
|
634
|
+
scope: Optional["Scope"] = None,
|
|
635
|
+
) -> bool:
|
|
655
636
|
# Transactions are sampled independent of error events.
|
|
656
637
|
is_transaction = event.get("type") == "transaction"
|
|
657
638
|
if is_transaction:
|
|
@@ -669,10 +650,9 @@ class _Client(BaseClient):
|
|
|
669
650
|
|
|
670
651
|
def _should_sample_error(
|
|
671
652
|
self,
|
|
672
|
-
event
|
|
673
|
-
hint
|
|
674
|
-
):
|
|
675
|
-
# type: (...) -> bool
|
|
653
|
+
event: Event,
|
|
654
|
+
hint: Hint,
|
|
655
|
+
) -> bool:
|
|
676
656
|
error_sampler = self.options.get("error_sampler", None)
|
|
677
657
|
|
|
678
658
|
if callable(error_sampler):
|
|
@@ -717,10 +697,9 @@ class _Client(BaseClient):
|
|
|
717
697
|
|
|
718
698
|
def _update_session_from_event(
|
|
719
699
|
self,
|
|
720
|
-
session
|
|
721
|
-
event
|
|
722
|
-
):
|
|
723
|
-
# type: (...) -> None
|
|
700
|
+
session: Session,
|
|
701
|
+
event: Event,
|
|
702
|
+
) -> None:
|
|
724
703
|
|
|
725
704
|
crashed = False
|
|
726
705
|
errored = False
|
|
@@ -756,11 +735,10 @@ class _Client(BaseClient):
|
|
|
756
735
|
|
|
757
736
|
def capture_event(
|
|
758
737
|
self,
|
|
759
|
-
event
|
|
760
|
-
hint
|
|
761
|
-
scope
|
|
762
|
-
):
|
|
763
|
-
# type: (...) -> Optional[str]
|
|
738
|
+
event: Event,
|
|
739
|
+
hint: Optional[Hint] = None,
|
|
740
|
+
scope: Optional[Scope] = None,
|
|
741
|
+
) -> Optional[str]:
|
|
764
742
|
"""Captures an event.
|
|
765
743
|
|
|
766
744
|
:param event: A ready-made event that can be directly sent to Sentry.
|
|
@@ -771,7 +749,7 @@ class _Client(BaseClient):
|
|
|
771
749
|
|
|
772
750
|
:returns: An event ID. May be `None` if there is no DSN set or of if the SDK decided to discard the event for other reasons. In such situations setting `debug=True` on `init()` may help.
|
|
773
751
|
"""
|
|
774
|
-
hint = dict(hint or ())
|
|
752
|
+
hint: Hint = dict(hint or ())
|
|
775
753
|
|
|
776
754
|
if not self._should_capture(event, hint, scope):
|
|
777
755
|
return None
|
|
@@ -806,10 +784,10 @@ class _Client(BaseClient):
|
|
|
806
784
|
trace_context = event_opt.get("contexts", {}).get("trace") or {}
|
|
807
785
|
dynamic_sampling_context = trace_context.pop("dynamic_sampling_context", {})
|
|
808
786
|
|
|
809
|
-
headers = {
|
|
787
|
+
headers: dict[str, object] = {
|
|
810
788
|
"event_id": event_opt["event_id"],
|
|
811
789
|
"sent_at": format_timestamp(datetime.now(timezone.utc)),
|
|
812
|
-
}
|
|
790
|
+
}
|
|
813
791
|
|
|
814
792
|
if dynamic_sampling_context:
|
|
815
793
|
headers["trace"] = dynamic_sampling_context
|
|
@@ -839,12 +817,13 @@ class _Client(BaseClient):
|
|
|
839
817
|
|
|
840
818
|
return return_value
|
|
841
819
|
|
|
842
|
-
def _capture_experimental_log(self,
|
|
843
|
-
# type: (Scope, Log) -> None
|
|
820
|
+
def _capture_experimental_log(self, log: Log) -> None:
|
|
844
821
|
logs_enabled = self.options["_experiments"].get("enable_logs", False)
|
|
845
822
|
if not logs_enabled:
|
|
846
823
|
return
|
|
847
|
-
|
|
824
|
+
|
|
825
|
+
current_scope = sentry_sdk.get_current_scope()
|
|
826
|
+
isolation_scope = sentry_sdk.get_isolation_scope()
|
|
848
827
|
|
|
849
828
|
log["attributes"]["sentry.sdk.name"] = SDK_INFO["name"]
|
|
850
829
|
log["attributes"]["sentry.sdk.version"] = SDK_INFO["version"]
|
|
@@ -873,6 +852,21 @@ class _Client(BaseClient):
|
|
|
873
852
|
elif propagation_context is not None:
|
|
874
853
|
log["trace_id"] = propagation_context.trace_id
|
|
875
854
|
|
|
855
|
+
# The user, if present, is always set on the isolation scope.
|
|
856
|
+
if isolation_scope._user is not None:
|
|
857
|
+
for log_attribute, user_attribute in (
|
|
858
|
+
("user.id", "id"),
|
|
859
|
+
("user.name", "username"),
|
|
860
|
+
("user.email", "email"),
|
|
861
|
+
):
|
|
862
|
+
if (
|
|
863
|
+
user_attribute in isolation_scope._user
|
|
864
|
+
and log_attribute not in log["attributes"]
|
|
865
|
+
):
|
|
866
|
+
log["attributes"][log_attribute] = isolation_scope._user[
|
|
867
|
+
user_attribute
|
|
868
|
+
]
|
|
869
|
+
|
|
876
870
|
# If debug is enabled, log the log to the console
|
|
877
871
|
debug = self.options.get("debug", False)
|
|
878
872
|
if debug:
|
|
@@ -889,10 +883,7 @@ class _Client(BaseClient):
|
|
|
889
883
|
if self.log_batcher:
|
|
890
884
|
self.log_batcher.add(log)
|
|
891
885
|
|
|
892
|
-
def capture_session(
|
|
893
|
-
self, session # type: Session
|
|
894
|
-
):
|
|
895
|
-
# type: (...) -> None
|
|
886
|
+
def capture_session(self, session: Session) -> None:
|
|
896
887
|
if not session.release:
|
|
897
888
|
logger.info("Discarded session update because of missing release")
|
|
898
889
|
else:
|
|
@@ -901,19 +892,16 @@ class _Client(BaseClient):
|
|
|
901
892
|
if TYPE_CHECKING:
|
|
902
893
|
|
|
903
894
|
@overload
|
|
904
|
-
def get_integration(self, name_or_class):
|
|
905
|
-
# type: (str) -> Optional[Integration]
|
|
906
|
-
...
|
|
895
|
+
def get_integration(self, name_or_class: str) -> Optional[Integration]: ...
|
|
907
896
|
|
|
908
897
|
@overload
|
|
909
|
-
def get_integration(
|
|
910
|
-
|
|
911
|
-
|
|
898
|
+
def get_integration(
|
|
899
|
+
self, name_or_class: type[IntegrationType]
|
|
900
|
+
) -> Optional[IntegrationType]: ...
|
|
912
901
|
|
|
913
902
|
def get_integration(
|
|
914
|
-
self, name_or_class
|
|
915
|
-
):
|
|
916
|
-
# type: (...) -> Optional[Integration]
|
|
903
|
+
self, name_or_class: Union[str, Type[Integration]]
|
|
904
|
+
) -> Optional[Integration]:
|
|
917
905
|
"""Returns the integration for this client by name or class.
|
|
918
906
|
If the client does not have that integration then `None` is returned.
|
|
919
907
|
"""
|
|
@@ -928,10 +916,9 @@ class _Client(BaseClient):
|
|
|
928
916
|
|
|
929
917
|
def close(
|
|
930
918
|
self,
|
|
931
|
-
timeout
|
|
932
|
-
callback
|
|
933
|
-
):
|
|
934
|
-
# type: (...) -> None
|
|
919
|
+
timeout: Optional[float] = None,
|
|
920
|
+
callback: Optional[Callable[[int, float], None]] = None,
|
|
921
|
+
) -> None:
|
|
935
922
|
"""
|
|
936
923
|
Close the client and shut down the transport. Arguments have the same
|
|
937
924
|
semantics as :py:meth:`Client.flush`.
|
|
@@ -952,10 +939,9 @@ class _Client(BaseClient):
|
|
|
952
939
|
|
|
953
940
|
def flush(
|
|
954
941
|
self,
|
|
955
|
-
timeout
|
|
956
|
-
callback
|
|
957
|
-
):
|
|
958
|
-
# type: (...) -> None
|
|
942
|
+
timeout: Optional[float] = None,
|
|
943
|
+
callback: Optional[Callable[[int, float], None]] = None,
|
|
944
|
+
) -> None:
|
|
959
945
|
"""
|
|
960
946
|
Wait for the current events to be sent.
|
|
961
947
|
|
|
@@ -973,17 +959,13 @@ class _Client(BaseClient):
|
|
|
973
959
|
|
|
974
960
|
self.transport.flush(timeout=timeout, callback=callback)
|
|
975
961
|
|
|
976
|
-
def __enter__(self):
|
|
977
|
-
# type: () -> _Client
|
|
962
|
+
def __enter__(self) -> _Client:
|
|
978
963
|
return self
|
|
979
964
|
|
|
980
|
-
def __exit__(self, exc_type, exc_value, tb):
|
|
981
|
-
# type: (Any, Any, Any) -> None
|
|
965
|
+
def __exit__(self, exc_type: Any, exc_value: Any, tb: Any) -> None:
|
|
982
966
|
self.close()
|
|
983
967
|
|
|
984
968
|
|
|
985
|
-
from typing import TYPE_CHECKING
|
|
986
|
-
|
|
987
969
|
if TYPE_CHECKING:
|
|
988
970
|
# Make mypy, PyCharm and other static analyzers think `get_options` is a
|
|
989
971
|
# type to have nicer autocompletion for params.
|