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
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
Code used for the Caches module in Sentry
|
|
3
3
|
"""
|
|
4
4
|
|
|
5
|
+
from __future__ import annotations
|
|
5
6
|
from sentry_sdk.consts import OP, SPANDATA
|
|
6
7
|
from sentry_sdk.integrations.redis.utils import _get_safe_key, _key_as_string
|
|
7
8
|
from sentry_sdk.utils import capture_internal_exceptions
|
|
@@ -16,8 +17,7 @@ if TYPE_CHECKING:
|
|
|
16
17
|
from typing import Any, Optional
|
|
17
18
|
|
|
18
19
|
|
|
19
|
-
def _get_op(name):
|
|
20
|
-
# type: (str) -> Optional[str]
|
|
20
|
+
def _get_op(name: str) -> Optional[str]:
|
|
21
21
|
op = None
|
|
22
22
|
if name.lower() in GET_COMMANDS:
|
|
23
23
|
op = OP.CACHE_GET
|
|
@@ -27,8 +27,12 @@ def _get_op(name):
|
|
|
27
27
|
return op
|
|
28
28
|
|
|
29
29
|
|
|
30
|
-
def _compile_cache_span_properties(
|
|
31
|
-
|
|
30
|
+
def _compile_cache_span_properties(
|
|
31
|
+
redis_command: str,
|
|
32
|
+
args: tuple[Any, ...],
|
|
33
|
+
kwargs: dict[str, Any],
|
|
34
|
+
integration: RedisIntegration,
|
|
35
|
+
) -> dict[str, Any]:
|
|
32
36
|
key = _get_safe_key(redis_command, args, kwargs)
|
|
33
37
|
key_as_string = _key_as_string(key)
|
|
34
38
|
keys_as_string = key_as_string.split(", ")
|
|
@@ -61,8 +65,12 @@ def _compile_cache_span_properties(redis_command, args, kwargs, integration):
|
|
|
61
65
|
return properties
|
|
62
66
|
|
|
63
67
|
|
|
64
|
-
def _get_cache_span_description(
|
|
65
|
-
|
|
68
|
+
def _get_cache_span_description(
|
|
69
|
+
redis_command: str,
|
|
70
|
+
args: tuple[Any, ...],
|
|
71
|
+
kwargs: dict[str, Any],
|
|
72
|
+
integration: RedisIntegration,
|
|
73
|
+
) -> str:
|
|
66
74
|
description = _key_as_string(_get_safe_key(redis_command, args, kwargs))
|
|
67
75
|
|
|
68
76
|
data_should_be_truncated = (
|
|
@@ -74,8 +82,9 @@ def _get_cache_span_description(redis_command, args, kwargs, integration):
|
|
|
74
82
|
return description
|
|
75
83
|
|
|
76
84
|
|
|
77
|
-
def _get_cache_data(
|
|
78
|
-
|
|
85
|
+
def _get_cache_data(
|
|
86
|
+
redis_client: Any, properties: dict[str, Any], return_value: Optional[Any]
|
|
87
|
+
) -> dict[str, Any]:
|
|
79
88
|
data = {}
|
|
80
89
|
|
|
81
90
|
with capture_internal_exceptions():
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
Code used for the Queries module in Sentry
|
|
3
3
|
"""
|
|
4
4
|
|
|
5
|
+
from __future__ import annotations
|
|
5
6
|
from sentry_sdk.consts import OP, SPANDATA
|
|
6
7
|
from sentry_sdk.integrations.redis.utils import _get_safe_command
|
|
7
8
|
from sentry_sdk.utils import capture_internal_exceptions
|
|
@@ -14,8 +15,9 @@ if TYPE_CHECKING:
|
|
|
14
15
|
from typing import Any
|
|
15
16
|
|
|
16
17
|
|
|
17
|
-
def _compile_db_span_properties(
|
|
18
|
-
|
|
18
|
+
def _compile_db_span_properties(
|
|
19
|
+
integration: RedisIntegration, redis_command: str, args: tuple[Any, ...]
|
|
20
|
+
) -> dict[str, Any]:
|
|
19
21
|
description = _get_db_span_description(integration, redis_command, args)
|
|
20
22
|
|
|
21
23
|
properties = {
|
|
@@ -26,8 +28,9 @@ def _compile_db_span_properties(integration, redis_command, args):
|
|
|
26
28
|
return properties
|
|
27
29
|
|
|
28
30
|
|
|
29
|
-
def _get_db_span_description(
|
|
30
|
-
|
|
31
|
+
def _get_db_span_description(
|
|
32
|
+
integration: RedisIntegration, command_name: str, args: tuple[Any, ...]
|
|
33
|
+
) -> str:
|
|
31
34
|
description = command_name
|
|
32
35
|
|
|
33
36
|
with capture_internal_exceptions():
|
|
@@ -42,8 +45,7 @@ def _get_db_span_description(integration, command_name, args):
|
|
|
42
45
|
return description
|
|
43
46
|
|
|
44
47
|
|
|
45
|
-
def _get_connection_data(connection_params):
|
|
46
|
-
# type: (dict[str, Any]) -> dict[str, Any]
|
|
48
|
+
def _get_connection_data(connection_params: dict[str, Any]) -> dict[str, Any]:
|
|
47
49
|
data = {
|
|
48
50
|
SPANDATA.DB_SYSTEM: "redis",
|
|
49
51
|
}
|
|
@@ -63,8 +65,7 @@ def _get_connection_data(connection_params):
|
|
|
63
65
|
return data
|
|
64
66
|
|
|
65
67
|
|
|
66
|
-
def _get_db_data(redis_instance):
|
|
67
|
-
# type: (Redis[Any]) -> dict[str, Any]
|
|
68
|
+
def _get_db_data(redis_instance: Redis[Any]) -> dict[str, Any]:
|
|
68
69
|
try:
|
|
69
70
|
return _get_connection_data(redis_instance.connection_pool.connection_kwargs)
|
|
70
71
|
except AttributeError:
|
|
@@ -4,12 +4,13 @@ Instrumentation for Redis Blaster (rb)
|
|
|
4
4
|
https://github.com/getsentry/rb
|
|
5
5
|
"""
|
|
6
6
|
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
7
9
|
from sentry_sdk.integrations.redis._sync_common import patch_redis_client
|
|
8
10
|
from sentry_sdk.integrations.redis.modules.queries import _get_db_data
|
|
9
11
|
|
|
10
12
|
|
|
11
|
-
def _patch_rb():
|
|
12
|
-
# type: () -> None
|
|
13
|
+
def _patch_rb() -> None:
|
|
13
14
|
try:
|
|
14
15
|
import rb.clients # type: ignore
|
|
15
16
|
except ImportError:
|
|
@@ -4,6 +4,8 @@ Instrumentation for Redis
|
|
|
4
4
|
https://github.com/redis/redis-py
|
|
5
5
|
"""
|
|
6
6
|
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
7
9
|
from sentry_sdk.integrations.redis._sync_common import (
|
|
8
10
|
patch_redis_client,
|
|
9
11
|
patch_redis_pipeline,
|
|
@@ -16,13 +18,11 @@ if TYPE_CHECKING:
|
|
|
16
18
|
from typing import Any, Sequence
|
|
17
19
|
|
|
18
20
|
|
|
19
|
-
def _get_redis_command_args(command):
|
|
20
|
-
# type: (Any) -> Sequence[Any]
|
|
21
|
+
def _get_redis_command_args(command: Any) -> Sequence[Any]:
|
|
21
22
|
return command[0]
|
|
22
23
|
|
|
23
24
|
|
|
24
|
-
def _patch_redis(StrictRedis, client): # noqa: N803
|
|
25
|
-
# type: (Any, Any) -> None
|
|
25
|
+
def _patch_redis(StrictRedis: Any, client: Any) -> None: # noqa: N803
|
|
26
26
|
patch_redis_client(
|
|
27
27
|
StrictRedis,
|
|
28
28
|
is_cluster=False,
|
|
@@ -5,6 +5,8 @@ This is part of the main redis-py client.
|
|
|
5
5
|
https://github.com/redis/redis-py/blob/master/redis/cluster.py
|
|
6
6
|
"""
|
|
7
7
|
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
8
10
|
from sentry_sdk.integrations.redis._sync_common import (
|
|
9
11
|
patch_redis_client,
|
|
10
12
|
patch_redis_pipeline,
|
|
@@ -25,8 +27,9 @@ if TYPE_CHECKING:
|
|
|
25
27
|
)
|
|
26
28
|
|
|
27
29
|
|
|
28
|
-
def _get_async_cluster_db_data(
|
|
29
|
-
|
|
30
|
+
def _get_async_cluster_db_data(
|
|
31
|
+
async_redis_cluster_instance: AsyncRedisCluster[Any],
|
|
32
|
+
) -> dict[str, Any]:
|
|
30
33
|
default_node = async_redis_cluster_instance.get_default_node()
|
|
31
34
|
if default_node is not None and default_node.connection_kwargs is not None:
|
|
32
35
|
return _get_connection_data(default_node.connection_kwargs)
|
|
@@ -34,18 +37,24 @@ def _get_async_cluster_db_data(async_redis_cluster_instance):
|
|
|
34
37
|
return {}
|
|
35
38
|
|
|
36
39
|
|
|
37
|
-
def _get_async_cluster_pipeline_db_data(
|
|
38
|
-
|
|
40
|
+
def _get_async_cluster_pipeline_db_data(
|
|
41
|
+
async_redis_cluster_pipeline_instance: AsyncClusterPipeline[Any],
|
|
42
|
+
) -> dict[str, Any]:
|
|
39
43
|
with capture_internal_exceptions():
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
#
|
|
43
|
-
|
|
44
|
-
|
|
44
|
+
client = getattr(async_redis_cluster_pipeline_instance, "cluster_client", None)
|
|
45
|
+
if client is None:
|
|
46
|
+
# In older redis-py versions, the AsyncClusterPipeline had a `_client`
|
|
47
|
+
# attr but it is private so potentially problematic and mypy does not
|
|
48
|
+
# recognize it - see
|
|
49
|
+
# https://github.com/redis/redis-py/blame/v5.0.0/redis/asyncio/cluster.py#L1386
|
|
50
|
+
client = (
|
|
51
|
+
async_redis_cluster_pipeline_instance._client # type: ignore[attr-defined]
|
|
52
|
+
)
|
|
53
|
+
|
|
54
|
+
return _get_async_cluster_db_data(client)
|
|
45
55
|
|
|
46
56
|
|
|
47
|
-
def _get_cluster_db_data(redis_cluster_instance):
|
|
48
|
-
# type: (RedisCluster[Any]) -> dict[str, Any]
|
|
57
|
+
def _get_cluster_db_data(redis_cluster_instance: RedisCluster[Any]) -> dict[str, Any]:
|
|
49
58
|
default_node = redis_cluster_instance.get_default_node()
|
|
50
59
|
|
|
51
60
|
if default_node is not None:
|
|
@@ -58,8 +67,7 @@ def _get_cluster_db_data(redis_cluster_instance):
|
|
|
58
67
|
return {}
|
|
59
68
|
|
|
60
69
|
|
|
61
|
-
def _patch_redis_cluster():
|
|
62
|
-
# type: () -> None
|
|
70
|
+
def _patch_redis_cluster() -> None:
|
|
63
71
|
"""Patches the cluster module on redis SDK (as opposed to rediscluster library)"""
|
|
64
72
|
try:
|
|
65
73
|
from redis import RedisCluster, cluster
|
|
@@ -5,6 +5,8 @@ The project redis-py-cluster is EOL and was integrated into redis-py starting fr
|
|
|
5
5
|
https://github.com/grokzen/redis-py-cluster
|
|
6
6
|
"""
|
|
7
7
|
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
8
10
|
from sentry_sdk.integrations.redis._sync_common import (
|
|
9
11
|
patch_redis_client,
|
|
10
12
|
patch_redis_pipeline,
|
|
@@ -13,8 +15,7 @@ from sentry_sdk.integrations.redis.modules.queries import _get_db_data
|
|
|
13
15
|
from sentry_sdk.integrations.redis.utils import _parse_rediscluster_command
|
|
14
16
|
|
|
15
17
|
|
|
16
|
-
def _patch_rediscluster():
|
|
17
|
-
# type: () -> None
|
|
18
|
+
def _patch_rediscluster() -> None:
|
|
18
19
|
try:
|
|
19
20
|
import rediscluster # type: ignore
|
|
20
21
|
except ImportError:
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
1
2
|
import sentry_sdk
|
|
2
3
|
from sentry_sdk.consts import SPANDATA
|
|
3
4
|
from sentry_sdk.integrations.redis.consts import (
|
|
@@ -26,8 +27,7 @@ TAG_KEYS = [
|
|
|
26
27
|
]
|
|
27
28
|
|
|
28
29
|
|
|
29
|
-
def _update_span(span, *data_bags):
|
|
30
|
-
# type: (Span, *dict[str, Any]) -> None
|
|
30
|
+
def _update_span(span: Span, *data_bags: dict[str, Any]) -> None:
|
|
31
31
|
"""
|
|
32
32
|
Set tags and data on the given span to data from the given data bags.
|
|
33
33
|
"""
|
|
@@ -39,8 +39,7 @@ def _update_span(span, *data_bags):
|
|
|
39
39
|
span.set_attribute(key, value)
|
|
40
40
|
|
|
41
41
|
|
|
42
|
-
def _create_breadcrumb(message, *data_bags):
|
|
43
|
-
# type: (str, *dict[str, Any]) -> None
|
|
42
|
+
def _create_breadcrumb(message: str, *data_bags: dict[str, Any]) -> None:
|
|
44
43
|
"""
|
|
45
44
|
Create a breadcrumb containing the tags data from the given data bags.
|
|
46
45
|
"""
|
|
@@ -58,8 +57,7 @@ def _create_breadcrumb(message, *data_bags):
|
|
|
58
57
|
)
|
|
59
58
|
|
|
60
59
|
|
|
61
|
-
def _get_safe_command(name, args):
|
|
62
|
-
# type: (str, Sequence[Any]) -> str
|
|
60
|
+
def _get_safe_command(name: str, args: Sequence[Any]) -> str:
|
|
63
61
|
command_parts = [name]
|
|
64
62
|
|
|
65
63
|
for i, arg in enumerate(args):
|
|
@@ -86,8 +84,7 @@ def _get_safe_command(name, args):
|
|
|
86
84
|
return command
|
|
87
85
|
|
|
88
86
|
|
|
89
|
-
def _safe_decode(key):
|
|
90
|
-
# type: (Any) -> str
|
|
87
|
+
def _safe_decode(key: Any) -> str:
|
|
91
88
|
if isinstance(key, bytes):
|
|
92
89
|
try:
|
|
93
90
|
return key.decode()
|
|
@@ -97,8 +94,7 @@ def _safe_decode(key):
|
|
|
97
94
|
return str(key)
|
|
98
95
|
|
|
99
96
|
|
|
100
|
-
def _key_as_string(key):
|
|
101
|
-
# type: (Any) -> str
|
|
97
|
+
def _key_as_string(key: Any) -> str:
|
|
102
98
|
if isinstance(key, (dict, list, tuple)):
|
|
103
99
|
key = ", ".join(_safe_decode(x) for x in key)
|
|
104
100
|
elif isinstance(key, bytes):
|
|
@@ -111,8 +107,9 @@ def _key_as_string(key):
|
|
|
111
107
|
return key
|
|
112
108
|
|
|
113
109
|
|
|
114
|
-
def _get_safe_key(
|
|
115
|
-
|
|
110
|
+
def _get_safe_key(
|
|
111
|
+
method_name: str, args: Optional[tuple[Any, ...]], kwargs: Optional[dict[str, Any]]
|
|
112
|
+
) -> Optional[tuple[str, ...]]:
|
|
116
113
|
"""
|
|
117
114
|
Gets the key (or keys) from the given method_name.
|
|
118
115
|
The method_name could be a redis command or a django caching command
|
|
@@ -142,37 +139,39 @@ def _get_safe_key(method_name, args, kwargs):
|
|
|
142
139
|
return key
|
|
143
140
|
|
|
144
141
|
|
|
145
|
-
def _parse_rediscluster_command(command):
|
|
146
|
-
# type: (Any) -> Sequence[Any]
|
|
142
|
+
def _parse_rediscluster_command(command: Any) -> Sequence[Any]:
|
|
147
143
|
return command.args
|
|
148
144
|
|
|
149
145
|
|
|
150
|
-
def _get_pipeline_data(
|
|
151
|
-
|
|
152
|
-
|
|
146
|
+
def _get_pipeline_data(
|
|
147
|
+
is_cluster: bool,
|
|
148
|
+
get_command_args_fn: Any,
|
|
149
|
+
is_transaction: bool,
|
|
150
|
+
command_seq: Sequence[Any],
|
|
151
|
+
) -> dict[str, Any]:
|
|
152
|
+
data: dict[str, Any] = {
|
|
153
153
|
"redis.is_cluster": is_cluster,
|
|
154
154
|
"redis.transaction": is_transaction,
|
|
155
|
-
}
|
|
155
|
+
}
|
|
156
156
|
|
|
157
157
|
commands = []
|
|
158
|
-
for i, arg in enumerate(
|
|
158
|
+
for i, arg in enumerate(command_seq):
|
|
159
159
|
if i >= _MAX_NUM_COMMANDS:
|
|
160
160
|
break
|
|
161
161
|
|
|
162
162
|
command = get_command_args_fn(arg)
|
|
163
163
|
commands.append(_get_safe_command(command[0], command[1:]))
|
|
164
164
|
|
|
165
|
-
data["redis.commands.count"] = len(
|
|
165
|
+
data["redis.commands.count"] = len(command_seq)
|
|
166
166
|
data["redis.commands.first_ten"] = commands
|
|
167
167
|
|
|
168
168
|
return data
|
|
169
169
|
|
|
170
170
|
|
|
171
|
-
def _get_client_data(is_cluster, name, *args):
|
|
172
|
-
|
|
173
|
-
data = {
|
|
171
|
+
def _get_client_data(is_cluster: bool, name: str, *args: Any) -> dict[str, Any]:
|
|
172
|
+
data: dict[str, Any] = {
|
|
174
173
|
"redis.is_cluster": is_cluster,
|
|
175
|
-
}
|
|
174
|
+
}
|
|
176
175
|
|
|
177
176
|
if name:
|
|
178
177
|
data["redis.command"] = name
|
sentry_sdk/integrations/rq.py
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
1
2
|
import weakref
|
|
2
3
|
|
|
3
4
|
import sentry_sdk
|
|
@@ -49,16 +50,16 @@ class RqIntegration(Integration):
|
|
|
49
50
|
origin = f"auto.queue.{identifier}"
|
|
50
51
|
|
|
51
52
|
@staticmethod
|
|
52
|
-
def setup_once():
|
|
53
|
-
# type: () -> None
|
|
53
|
+
def setup_once() -> None:
|
|
54
54
|
version = parse_version(RQ_VERSION)
|
|
55
55
|
_check_minimum_version(RqIntegration, version)
|
|
56
56
|
|
|
57
57
|
old_perform_job = Worker.perform_job
|
|
58
58
|
|
|
59
59
|
@ensure_integration_enabled(RqIntegration, old_perform_job)
|
|
60
|
-
def sentry_patched_perform_job(
|
|
61
|
-
|
|
60
|
+
def sentry_patched_perform_job(
|
|
61
|
+
self: Any, job: Job, queue: Queue, *args: Any, **kwargs: Any
|
|
62
|
+
) -> bool:
|
|
62
63
|
with sentry_sdk.new_scope() as scope:
|
|
63
64
|
try:
|
|
64
65
|
transaction_name = job.func_name or DEFAULT_TRANSACTION_NAME
|
|
@@ -95,8 +96,9 @@ class RqIntegration(Integration):
|
|
|
95
96
|
|
|
96
97
|
old_handle_exception = Worker.handle_exception
|
|
97
98
|
|
|
98
|
-
def sentry_patched_handle_exception(
|
|
99
|
-
|
|
99
|
+
def sentry_patched_handle_exception(
|
|
100
|
+
self: Worker, job: Any, *exc_info: Any, **kwargs: Any
|
|
101
|
+
) -> Any:
|
|
100
102
|
retry = (
|
|
101
103
|
hasattr(job, "retries_left")
|
|
102
104
|
and job.retries_left
|
|
@@ -113,8 +115,7 @@ class RqIntegration(Integration):
|
|
|
113
115
|
old_enqueue_job = Queue.enqueue_job
|
|
114
116
|
|
|
115
117
|
@ensure_integration_enabled(RqIntegration, old_enqueue_job)
|
|
116
|
-
def sentry_patched_enqueue_job(self, job, **kwargs):
|
|
117
|
-
# type: (Queue, Any, **Any) -> Any
|
|
118
|
+
def sentry_patched_enqueue_job(self: Queue, job: Any, **kwargs: Any) -> Any:
|
|
118
119
|
job.meta["_sentry_trace_headers"] = dict(
|
|
119
120
|
sentry_sdk.get_current_scope().iter_trace_propagation_headers()
|
|
120
121
|
)
|
|
@@ -126,10 +127,8 @@ class RqIntegration(Integration):
|
|
|
126
127
|
ignore_logger("rq.worker")
|
|
127
128
|
|
|
128
129
|
|
|
129
|
-
def _make_event_processor(weak_job):
|
|
130
|
-
|
|
131
|
-
def event_processor(event, hint):
|
|
132
|
-
# type: (Event, dict[str, Any]) -> Event
|
|
130
|
+
def _make_event_processor(weak_job: Callable[[], Job]) -> EventProcessor:
|
|
131
|
+
def event_processor(event: Event, hint: dict[str, Any]) -> Event:
|
|
133
132
|
job = weak_job()
|
|
134
133
|
if job is not None:
|
|
135
134
|
with capture_internal_exceptions():
|
|
@@ -159,8 +158,7 @@ def _make_event_processor(weak_job):
|
|
|
159
158
|
return event_processor
|
|
160
159
|
|
|
161
160
|
|
|
162
|
-
def _capture_exception(exc_info, **kwargs):
|
|
163
|
-
# type: (ExcInfo, **Any) -> None
|
|
161
|
+
def _capture_exception(exc_info: ExcInfo, **kwargs: Any) -> None:
|
|
164
162
|
client = sentry_sdk.get_client()
|
|
165
163
|
|
|
166
164
|
event, hint = event_from_exception(
|
|
@@ -172,8 +170,7 @@ def _capture_exception(exc_info, **kwargs):
|
|
|
172
170
|
sentry_sdk.capture_event(event, hint=hint)
|
|
173
171
|
|
|
174
172
|
|
|
175
|
-
def _prepopulate_attributes(job, queue):
|
|
176
|
-
# type: (Job, Queue) -> dict[str, Any]
|
|
173
|
+
def _prepopulate_attributes(job: Job, queue: Queue) -> dict[str, Any]:
|
|
177
174
|
attributes = {
|
|
178
175
|
"messaging.system": "rq",
|
|
179
176
|
"rq.job.id": job.id,
|
|
@@ -30,9 +30,13 @@ sentry_sdk.init(
|
|
|
30
30
|
Each native extension requires its own integration.
|
|
31
31
|
"""
|
|
32
32
|
|
|
33
|
+
from __future__ import annotations
|
|
33
34
|
import json
|
|
34
35
|
from enum import Enum, auto
|
|
35
|
-
from typing import
|
|
36
|
+
from typing import TYPE_CHECKING
|
|
37
|
+
|
|
38
|
+
if TYPE_CHECKING:
|
|
39
|
+
from typing import Any, Callable, Dict, Optional
|
|
36
40
|
|
|
37
41
|
import sentry_sdk
|
|
38
42
|
from sentry_sdk.integrations import Integration
|
|
@@ -56,8 +60,7 @@ class EventTypeMapping(Enum):
|
|
|
56
60
|
Event = auto()
|
|
57
61
|
|
|
58
62
|
|
|
59
|
-
def tracing_level_to_sentry_level(level):
|
|
60
|
-
# type: (str) -> sentry_sdk._types.LogLevelStr
|
|
63
|
+
def tracing_level_to_sentry_level(level: str) -> sentry_sdk._types.LogLevelStr:
|
|
61
64
|
level = RustTracingLevel(level)
|
|
62
65
|
if level in (RustTracingLevel.Trace, RustTracingLevel.Debug):
|
|
63
66
|
return "debug"
|
|
@@ -97,15 +100,15 @@ def process_event(event: Dict[str, Any]) -> None:
|
|
|
97
100
|
|
|
98
101
|
logger = metadata.get("target")
|
|
99
102
|
level = tracing_level_to_sentry_level(metadata.get("level"))
|
|
100
|
-
message = event.get("message")
|
|
103
|
+
message: sentry_sdk._types.Any = event.get("message")
|
|
101
104
|
contexts = extract_contexts(event)
|
|
102
105
|
|
|
103
|
-
sentry_event = {
|
|
106
|
+
sentry_event: sentry_sdk._types.Event = {
|
|
104
107
|
"logger": logger,
|
|
105
108
|
"level": level,
|
|
106
109
|
"message": message,
|
|
107
110
|
"contexts": contexts,
|
|
108
|
-
}
|
|
111
|
+
}
|
|
109
112
|
|
|
110
113
|
sentry_sdk.capture_event(sentry_event)
|
|
111
114
|
|
sentry_sdk/integrations/sanic.py
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
1
2
|
import sys
|
|
2
3
|
import weakref
|
|
3
4
|
from inspect import isawaitable
|
|
@@ -59,8 +60,9 @@ class SanicIntegration(Integration):
|
|
|
59
60
|
origin = f"auto.http.{identifier}"
|
|
60
61
|
version = None
|
|
61
62
|
|
|
62
|
-
def __init__(
|
|
63
|
-
|
|
63
|
+
def __init__(
|
|
64
|
+
self, unsampled_statuses: Optional[Container[int]] = frozenset({404})
|
|
65
|
+
) -> None:
|
|
64
66
|
"""
|
|
65
67
|
The unsampled_statuses parameter can be used to specify for which HTTP statuses the
|
|
66
68
|
transactions should not be sent to Sentry. By default, transactions are sent for all
|
|
@@ -70,8 +72,7 @@ class SanicIntegration(Integration):
|
|
|
70
72
|
self._unsampled_statuses = unsampled_statuses or set()
|
|
71
73
|
|
|
72
74
|
@staticmethod
|
|
73
|
-
def setup_once():
|
|
74
|
-
# type: () -> None
|
|
75
|
+
def setup_once() -> None:
|
|
75
76
|
SanicIntegration.version = parse_version(SANIC_VERSION)
|
|
76
77
|
_check_minimum_version(SanicIntegration, SanicIntegration.version)
|
|
77
78
|
|
|
@@ -103,56 +104,45 @@ class SanicIntegration(Integration):
|
|
|
103
104
|
|
|
104
105
|
|
|
105
106
|
class SanicRequestExtractor(RequestExtractor):
|
|
106
|
-
def content_length(self):
|
|
107
|
-
# type: () -> int
|
|
107
|
+
def content_length(self) -> int:
|
|
108
108
|
if self.request.body is None:
|
|
109
109
|
return 0
|
|
110
110
|
return len(self.request.body)
|
|
111
111
|
|
|
112
|
-
def cookies(self):
|
|
113
|
-
# type: () -> Dict[str, str]
|
|
112
|
+
def cookies(self) -> Dict[str, str]:
|
|
114
113
|
return dict(self.request.cookies)
|
|
115
114
|
|
|
116
|
-
def raw_data(self):
|
|
117
|
-
# type: () -> bytes
|
|
115
|
+
def raw_data(self) -> bytes:
|
|
118
116
|
return self.request.body
|
|
119
117
|
|
|
120
|
-
def form(self):
|
|
121
|
-
# type: () -> RequestParameters
|
|
118
|
+
def form(self) -> RequestParameters:
|
|
122
119
|
return self.request.form
|
|
123
120
|
|
|
124
|
-
def is_json(self):
|
|
125
|
-
# type: () -> bool
|
|
121
|
+
def is_json(self) -> bool:
|
|
126
122
|
raise NotImplementedError()
|
|
127
123
|
|
|
128
|
-
def json(self):
|
|
129
|
-
# type: () -> Optional[Any]
|
|
124
|
+
def json(self) -> Optional[Any]:
|
|
130
125
|
return self.request.json
|
|
131
126
|
|
|
132
|
-
def files(self):
|
|
133
|
-
# type: () -> RequestParameters
|
|
127
|
+
def files(self) -> RequestParameters:
|
|
134
128
|
return self.request.files
|
|
135
129
|
|
|
136
|
-
def size_of_file(self, file):
|
|
137
|
-
# type: (Any) -> int
|
|
130
|
+
def size_of_file(self, file: Any) -> int:
|
|
138
131
|
return len(file.body or ())
|
|
139
132
|
|
|
140
133
|
|
|
141
|
-
def _setup_sanic():
|
|
142
|
-
# type: () -> None
|
|
134
|
+
def _setup_sanic() -> None:
|
|
143
135
|
Sanic._startup = _startup
|
|
144
136
|
ErrorHandler.lookup = _sentry_error_handler_lookup
|
|
145
137
|
|
|
146
138
|
|
|
147
|
-
def _setup_legacy_sanic():
|
|
148
|
-
# type: () -> None
|
|
139
|
+
def _setup_legacy_sanic() -> None:
|
|
149
140
|
Sanic.handle_request = _legacy_handle_request
|
|
150
141
|
Router.get = _legacy_router_get
|
|
151
142
|
ErrorHandler.lookup = _sentry_error_handler_lookup
|
|
152
143
|
|
|
153
144
|
|
|
154
|
-
async def _startup(self):
|
|
155
|
-
# type: (Sanic) -> None
|
|
145
|
+
async def _startup(self: Sanic) -> None:
|
|
156
146
|
# This happens about as early in the lifecycle as possible, just after the
|
|
157
147
|
# Request object is created. The body has not yet been consumed.
|
|
158
148
|
self.signal("http.lifecycle.request")(_context_enter)
|
|
@@ -171,8 +161,7 @@ async def _startup(self):
|
|
|
171
161
|
await old_startup(self)
|
|
172
162
|
|
|
173
163
|
|
|
174
|
-
async def _context_enter(request):
|
|
175
|
-
# type: (Request) -> None
|
|
164
|
+
async def _context_enter(request: Request) -> None:
|
|
176
165
|
request.ctx._sentry_do_integration = (
|
|
177
166
|
sentry_sdk.get_client().get_integration(SanicIntegration) is not None
|
|
178
167
|
)
|
|
@@ -203,8 +192,9 @@ async def _context_enter(request):
|
|
|
203
192
|
).__enter__()
|
|
204
193
|
|
|
205
194
|
|
|
206
|
-
async def _context_exit(
|
|
207
|
-
|
|
195
|
+
async def _context_exit(
|
|
196
|
+
request: Request, response: Optional[BaseHTTPResponse] = None
|
|
197
|
+
) -> None:
|
|
208
198
|
with capture_internal_exceptions():
|
|
209
199
|
if not request.ctx._sentry_do_integration:
|
|
210
200
|
return
|
|
@@ -233,8 +223,7 @@ async def _context_exit(request, response=None):
|
|
|
233
223
|
request.ctx._sentry_scope_manager.__exit__(None, None, None)
|
|
234
224
|
|
|
235
225
|
|
|
236
|
-
async def _set_transaction(request, route, **_):
|
|
237
|
-
# type: (Request, Route, **Any) -> None
|
|
226
|
+
async def _set_transaction(request: Request, route: Route, **_: Any) -> None:
|
|
238
227
|
if request.ctx._sentry_do_integration:
|
|
239
228
|
with capture_internal_exceptions():
|
|
240
229
|
scope = sentry_sdk.get_current_scope()
|
|
@@ -242,8 +231,9 @@ async def _set_transaction(request, route, **_):
|
|
|
242
231
|
scope.set_transaction_name(route_name, source=TransactionSource.COMPONENT)
|
|
243
232
|
|
|
244
233
|
|
|
245
|
-
def _sentry_error_handler_lookup(
|
|
246
|
-
|
|
234
|
+
def _sentry_error_handler_lookup(
|
|
235
|
+
self: Any, exception: Exception, *args: Any, **kwargs: Any
|
|
236
|
+
) -> Optional[object]:
|
|
247
237
|
_capture_exception(exception)
|
|
248
238
|
old_error_handler = old_error_handler_lookup(self, exception, *args, **kwargs)
|
|
249
239
|
|
|
@@ -253,8 +243,9 @@ def _sentry_error_handler_lookup(self, exception, *args, **kwargs):
|
|
|
253
243
|
if sentry_sdk.get_client().get_integration(SanicIntegration) is None:
|
|
254
244
|
return old_error_handler
|
|
255
245
|
|
|
256
|
-
async def sentry_wrapped_error_handler(
|
|
257
|
-
|
|
246
|
+
async def sentry_wrapped_error_handler(
|
|
247
|
+
request: Request, exception: Exception
|
|
248
|
+
) -> Any:
|
|
258
249
|
try:
|
|
259
250
|
response = old_error_handler(request, exception)
|
|
260
251
|
if isawaitable(response):
|
|
@@ -276,8 +267,9 @@ def _sentry_error_handler_lookup(self, exception, *args, **kwargs):
|
|
|
276
267
|
return sentry_wrapped_error_handler
|
|
277
268
|
|
|
278
269
|
|
|
279
|
-
async def _legacy_handle_request(
|
|
280
|
-
|
|
270
|
+
async def _legacy_handle_request(
|
|
271
|
+
self: Any, request: Request, *args: Any, **kwargs: Any
|
|
272
|
+
) -> Any:
|
|
281
273
|
if sentry_sdk.get_client().get_integration(SanicIntegration) is None:
|
|
282
274
|
return await old_handle_request(self, request, *args, **kwargs)
|
|
283
275
|
|
|
@@ -294,8 +286,7 @@ async def _legacy_handle_request(self, request, *args, **kwargs):
|
|
|
294
286
|
return response
|
|
295
287
|
|
|
296
288
|
|
|
297
|
-
def _legacy_router_get(self, *args):
|
|
298
|
-
# type: (Any, Union[Any, Request]) -> Any
|
|
289
|
+
def _legacy_router_get(self: Any, *args: Union[Any, Request]) -> Any:
|
|
299
290
|
rv = old_router_get(self, *args)
|
|
300
291
|
if sentry_sdk.get_client().get_integration(SanicIntegration) is not None:
|
|
301
292
|
with capture_internal_exceptions():
|
|
@@ -325,8 +316,7 @@ def _legacy_router_get(self, *args):
|
|
|
325
316
|
|
|
326
317
|
|
|
327
318
|
@ensure_integration_enabled(SanicIntegration)
|
|
328
|
-
def _capture_exception(exception):
|
|
329
|
-
# type: (Union[ExcInfo, BaseException]) -> None
|
|
319
|
+
def _capture_exception(exception: Union[ExcInfo, BaseException]) -> None:
|
|
330
320
|
with capture_internal_exceptions():
|
|
331
321
|
event, hint = event_from_exception(
|
|
332
322
|
exception,
|
|
@@ -340,10 +330,8 @@ def _capture_exception(exception):
|
|
|
340
330
|
sentry_sdk.capture_event(event, hint=hint)
|
|
341
331
|
|
|
342
332
|
|
|
343
|
-
def _make_request_processor(weak_request):
|
|
344
|
-
|
|
345
|
-
def sanic_processor(event, hint):
|
|
346
|
-
# type: (Event, Optional[Hint]) -> Optional[Event]
|
|
333
|
+
def _make_request_processor(weak_request: Callable[[], Request]) -> EventProcessor:
|
|
334
|
+
def sanic_processor(event: Event, hint: Optional[Hint]) -> Optional[Event]:
|
|
347
335
|
|
|
348
336
|
try:
|
|
349
337
|
if hint and issubclass(hint["exc_info"][0], SanicException):
|