sentry-sdk 0.7.5__py2.py3-none-any.whl → 2.46.0__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.
- sentry_sdk/__init__.py +48 -30
- sentry_sdk/_compat.py +74 -61
- sentry_sdk/_init_implementation.py +84 -0
- sentry_sdk/_log_batcher.py +172 -0
- sentry_sdk/_lru_cache.py +47 -0
- sentry_sdk/_metrics_batcher.py +167 -0
- sentry_sdk/_queue.py +289 -0
- sentry_sdk/_types.py +338 -0
- sentry_sdk/_werkzeug.py +98 -0
- sentry_sdk/ai/__init__.py +7 -0
- sentry_sdk/ai/monitoring.py +137 -0
- sentry_sdk/ai/utils.py +144 -0
- sentry_sdk/api.py +496 -80
- sentry_sdk/attachments.py +75 -0
- sentry_sdk/client.py +1023 -103
- sentry_sdk/consts.py +1438 -66
- sentry_sdk/crons/__init__.py +10 -0
- sentry_sdk/crons/api.py +62 -0
- sentry_sdk/crons/consts.py +4 -0
- sentry_sdk/crons/decorator.py +135 -0
- sentry_sdk/debug.py +15 -14
- sentry_sdk/envelope.py +369 -0
- sentry_sdk/feature_flags.py +71 -0
- sentry_sdk/hub.py +611 -280
- sentry_sdk/integrations/__init__.py +276 -49
- sentry_sdk/integrations/_asgi_common.py +108 -0
- sentry_sdk/integrations/_wsgi_common.py +180 -44
- sentry_sdk/integrations/aiohttp.py +291 -42
- sentry_sdk/integrations/anthropic.py +439 -0
- sentry_sdk/integrations/argv.py +9 -8
- sentry_sdk/integrations/ariadne.py +161 -0
- sentry_sdk/integrations/arq.py +247 -0
- sentry_sdk/integrations/asgi.py +341 -0
- sentry_sdk/integrations/asyncio.py +144 -0
- sentry_sdk/integrations/asyncpg.py +208 -0
- sentry_sdk/integrations/atexit.py +17 -10
- sentry_sdk/integrations/aws_lambda.py +377 -62
- sentry_sdk/integrations/beam.py +176 -0
- sentry_sdk/integrations/boto3.py +137 -0
- sentry_sdk/integrations/bottle.py +221 -0
- sentry_sdk/integrations/celery/__init__.py +529 -0
- sentry_sdk/integrations/celery/beat.py +293 -0
- sentry_sdk/integrations/celery/utils.py +43 -0
- sentry_sdk/integrations/chalice.py +134 -0
- sentry_sdk/integrations/clickhouse_driver.py +177 -0
- sentry_sdk/integrations/cloud_resource_context.py +280 -0
- sentry_sdk/integrations/cohere.py +274 -0
- sentry_sdk/integrations/dedupe.py +48 -14
- sentry_sdk/integrations/django/__init__.py +584 -191
- sentry_sdk/integrations/django/asgi.py +245 -0
- sentry_sdk/integrations/django/caching.py +204 -0
- sentry_sdk/integrations/django/middleware.py +187 -0
- sentry_sdk/integrations/django/signals_handlers.py +91 -0
- sentry_sdk/integrations/django/templates.py +79 -5
- sentry_sdk/integrations/django/transactions.py +49 -22
- sentry_sdk/integrations/django/views.py +96 -0
- sentry_sdk/integrations/dramatiq.py +226 -0
- sentry_sdk/integrations/excepthook.py +50 -13
- sentry_sdk/integrations/executing.py +67 -0
- sentry_sdk/integrations/falcon.py +272 -0
- sentry_sdk/integrations/fastapi.py +141 -0
- sentry_sdk/integrations/flask.py +142 -88
- sentry_sdk/integrations/gcp.py +239 -0
- sentry_sdk/integrations/gnu_backtrace.py +99 -0
- sentry_sdk/integrations/google_genai/__init__.py +301 -0
- sentry_sdk/integrations/google_genai/consts.py +16 -0
- sentry_sdk/integrations/google_genai/streaming.py +155 -0
- sentry_sdk/integrations/google_genai/utils.py +576 -0
- sentry_sdk/integrations/gql.py +162 -0
- sentry_sdk/integrations/graphene.py +151 -0
- sentry_sdk/integrations/grpc/__init__.py +168 -0
- sentry_sdk/integrations/grpc/aio/__init__.py +7 -0
- sentry_sdk/integrations/grpc/aio/client.py +95 -0
- sentry_sdk/integrations/grpc/aio/server.py +100 -0
- sentry_sdk/integrations/grpc/client.py +91 -0
- sentry_sdk/integrations/grpc/consts.py +1 -0
- sentry_sdk/integrations/grpc/server.py +66 -0
- sentry_sdk/integrations/httpx.py +178 -0
- sentry_sdk/integrations/huey.py +174 -0
- sentry_sdk/integrations/huggingface_hub.py +378 -0
- sentry_sdk/integrations/langchain.py +1132 -0
- sentry_sdk/integrations/langgraph.py +337 -0
- sentry_sdk/integrations/launchdarkly.py +61 -0
- sentry_sdk/integrations/litellm.py +287 -0
- sentry_sdk/integrations/litestar.py +315 -0
- sentry_sdk/integrations/logging.py +307 -96
- sentry_sdk/integrations/loguru.py +213 -0
- sentry_sdk/integrations/mcp.py +566 -0
- sentry_sdk/integrations/modules.py +14 -31
- sentry_sdk/integrations/openai.py +725 -0
- sentry_sdk/integrations/openai_agents/__init__.py +61 -0
- sentry_sdk/integrations/openai_agents/consts.py +1 -0
- sentry_sdk/integrations/openai_agents/patches/__init__.py +5 -0
- sentry_sdk/integrations/openai_agents/patches/agent_run.py +140 -0
- sentry_sdk/integrations/openai_agents/patches/error_tracing.py +77 -0
- sentry_sdk/integrations/openai_agents/patches/models.py +50 -0
- sentry_sdk/integrations/openai_agents/patches/runner.py +45 -0
- sentry_sdk/integrations/openai_agents/patches/tools.py +77 -0
- sentry_sdk/integrations/openai_agents/spans/__init__.py +5 -0
- sentry_sdk/integrations/openai_agents/spans/agent_workflow.py +21 -0
- sentry_sdk/integrations/openai_agents/spans/ai_client.py +42 -0
- sentry_sdk/integrations/openai_agents/spans/execute_tool.py +48 -0
- sentry_sdk/integrations/openai_agents/spans/handoff.py +19 -0
- sentry_sdk/integrations/openai_agents/spans/invoke_agent.py +86 -0
- sentry_sdk/integrations/openai_agents/utils.py +199 -0
- sentry_sdk/integrations/openfeature.py +35 -0
- sentry_sdk/integrations/opentelemetry/__init__.py +7 -0
- sentry_sdk/integrations/opentelemetry/consts.py +5 -0
- sentry_sdk/integrations/opentelemetry/integration.py +58 -0
- sentry_sdk/integrations/opentelemetry/propagator.py +117 -0
- sentry_sdk/integrations/opentelemetry/span_processor.py +391 -0
- sentry_sdk/integrations/otlp.py +82 -0
- sentry_sdk/integrations/pure_eval.py +141 -0
- sentry_sdk/integrations/pydantic_ai/__init__.py +47 -0
- sentry_sdk/integrations/pydantic_ai/consts.py +1 -0
- sentry_sdk/integrations/pydantic_ai/patches/__init__.py +4 -0
- sentry_sdk/integrations/pydantic_ai/patches/agent_run.py +215 -0
- sentry_sdk/integrations/pydantic_ai/patches/graph_nodes.py +110 -0
- sentry_sdk/integrations/pydantic_ai/patches/model_request.py +40 -0
- sentry_sdk/integrations/pydantic_ai/patches/tools.py +98 -0
- sentry_sdk/integrations/pydantic_ai/spans/__init__.py +3 -0
- sentry_sdk/integrations/pydantic_ai/spans/ai_client.py +246 -0
- sentry_sdk/integrations/pydantic_ai/spans/execute_tool.py +49 -0
- sentry_sdk/integrations/pydantic_ai/spans/invoke_agent.py +112 -0
- sentry_sdk/integrations/pydantic_ai/utils.py +223 -0
- sentry_sdk/integrations/pymongo.py +214 -0
- sentry_sdk/integrations/pyramid.py +112 -68
- sentry_sdk/integrations/quart.py +237 -0
- sentry_sdk/integrations/ray.py +165 -0
- sentry_sdk/integrations/redis/__init__.py +48 -0
- sentry_sdk/integrations/redis/_async_common.py +116 -0
- sentry_sdk/integrations/redis/_sync_common.py +119 -0
- sentry_sdk/integrations/redis/consts.py +19 -0
- sentry_sdk/integrations/redis/modules/__init__.py +0 -0
- sentry_sdk/integrations/redis/modules/caches.py +118 -0
- sentry_sdk/integrations/redis/modules/queries.py +65 -0
- sentry_sdk/integrations/redis/rb.py +32 -0
- sentry_sdk/integrations/redis/redis.py +69 -0
- sentry_sdk/integrations/redis/redis_cluster.py +107 -0
- sentry_sdk/integrations/redis/redis_py_cluster_legacy.py +50 -0
- sentry_sdk/integrations/redis/utils.py +148 -0
- sentry_sdk/integrations/rq.py +95 -37
- sentry_sdk/integrations/rust_tracing.py +284 -0
- sentry_sdk/integrations/sanic.py +294 -123
- sentry_sdk/integrations/serverless.py +48 -19
- sentry_sdk/integrations/socket.py +96 -0
- sentry_sdk/integrations/spark/__init__.py +4 -0
- sentry_sdk/integrations/spark/spark_driver.py +316 -0
- sentry_sdk/integrations/spark/spark_worker.py +116 -0
- sentry_sdk/integrations/sqlalchemy.py +142 -0
- sentry_sdk/integrations/starlette.py +737 -0
- sentry_sdk/integrations/starlite.py +292 -0
- sentry_sdk/integrations/statsig.py +37 -0
- sentry_sdk/integrations/stdlib.py +235 -29
- sentry_sdk/integrations/strawberry.py +394 -0
- sentry_sdk/integrations/sys_exit.py +70 -0
- sentry_sdk/integrations/threading.py +158 -28
- sentry_sdk/integrations/tornado.py +84 -52
- sentry_sdk/integrations/trytond.py +50 -0
- sentry_sdk/integrations/typer.py +60 -0
- sentry_sdk/integrations/unleash.py +33 -0
- sentry_sdk/integrations/unraisablehook.py +53 -0
- sentry_sdk/integrations/wsgi.py +201 -119
- sentry_sdk/logger.py +96 -0
- sentry_sdk/metrics.py +81 -0
- sentry_sdk/monitor.py +120 -0
- sentry_sdk/profiler/__init__.py +49 -0
- sentry_sdk/profiler/continuous_profiler.py +730 -0
- sentry_sdk/profiler/transaction_profiler.py +839 -0
- sentry_sdk/profiler/utils.py +195 -0
- sentry_sdk/py.typed +0 -0
- sentry_sdk/scope.py +1713 -85
- sentry_sdk/scrubber.py +177 -0
- sentry_sdk/serializer.py +405 -0
- sentry_sdk/session.py +177 -0
- sentry_sdk/sessions.py +275 -0
- sentry_sdk/spotlight.py +242 -0
- sentry_sdk/tracing.py +1486 -0
- sentry_sdk/tracing_utils.py +1236 -0
- sentry_sdk/transport.py +806 -134
- sentry_sdk/types.py +52 -0
- sentry_sdk/utils.py +1625 -465
- sentry_sdk/worker.py +54 -25
- sentry_sdk-2.46.0.dist-info/METADATA +268 -0
- sentry_sdk-2.46.0.dist-info/RECORD +189 -0
- {sentry_sdk-0.7.5.dist-info → sentry_sdk-2.46.0.dist-info}/WHEEL +1 -1
- sentry_sdk-2.46.0.dist-info/entry_points.txt +2 -0
- sentry_sdk-2.46.0.dist-info/licenses/LICENSE +21 -0
- sentry_sdk/integrations/celery.py +0 -119
- sentry_sdk-0.7.5.dist-info/LICENSE +0 -9
- sentry_sdk-0.7.5.dist-info/METADATA +0 -36
- sentry_sdk-0.7.5.dist-info/RECORD +0 -39
- {sentry_sdk-0.7.5.dist-info → sentry_sdk-2.46.0.dist-info}/top_level.txt +0 -0
sentry_sdk/ai/utils.py
ADDED
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
import json
|
|
2
|
+
from collections import deque
|
|
3
|
+
from typing import TYPE_CHECKING
|
|
4
|
+
from sys import getsizeof
|
|
5
|
+
|
|
6
|
+
if TYPE_CHECKING:
|
|
7
|
+
from typing import Any, Callable, Dict, List, Optional, Tuple
|
|
8
|
+
|
|
9
|
+
from sentry_sdk.tracing import Span
|
|
10
|
+
|
|
11
|
+
import sentry_sdk
|
|
12
|
+
from sentry_sdk.utils import logger
|
|
13
|
+
|
|
14
|
+
MAX_GEN_AI_MESSAGE_BYTES = 20_000 # 20KB
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class GEN_AI_ALLOWED_MESSAGE_ROLES:
|
|
18
|
+
SYSTEM = "system"
|
|
19
|
+
USER = "user"
|
|
20
|
+
ASSISTANT = "assistant"
|
|
21
|
+
TOOL = "tool"
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
GEN_AI_MESSAGE_ROLE_REVERSE_MAPPING = {
|
|
25
|
+
GEN_AI_ALLOWED_MESSAGE_ROLES.SYSTEM: ["system"],
|
|
26
|
+
GEN_AI_ALLOWED_MESSAGE_ROLES.USER: ["user", "human"],
|
|
27
|
+
GEN_AI_ALLOWED_MESSAGE_ROLES.ASSISTANT: ["assistant", "ai"],
|
|
28
|
+
GEN_AI_ALLOWED_MESSAGE_ROLES.TOOL: ["tool", "tool_call"],
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
GEN_AI_MESSAGE_ROLE_MAPPING = {}
|
|
32
|
+
for target_role, source_roles in GEN_AI_MESSAGE_ROLE_REVERSE_MAPPING.items():
|
|
33
|
+
for source_role in source_roles:
|
|
34
|
+
GEN_AI_MESSAGE_ROLE_MAPPING[source_role] = target_role
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def _normalize_data(data, unpack=True):
|
|
38
|
+
# type: (Any, bool) -> Any
|
|
39
|
+
# convert pydantic data (e.g. OpenAI v1+) to json compatible format
|
|
40
|
+
if hasattr(data, "model_dump"):
|
|
41
|
+
try:
|
|
42
|
+
return _normalize_data(data.model_dump(), unpack=unpack)
|
|
43
|
+
except Exception as e:
|
|
44
|
+
logger.warning("Could not convert pydantic data to JSON: %s", e)
|
|
45
|
+
return data if isinstance(data, (int, float, bool, str)) else str(data)
|
|
46
|
+
|
|
47
|
+
if isinstance(data, list):
|
|
48
|
+
if unpack and len(data) == 1:
|
|
49
|
+
return _normalize_data(data[0], unpack=unpack) # remove empty dimensions
|
|
50
|
+
return list(_normalize_data(x, unpack=unpack) for x in data)
|
|
51
|
+
|
|
52
|
+
if isinstance(data, dict):
|
|
53
|
+
return {k: _normalize_data(v, unpack=unpack) for (k, v) in data.items()}
|
|
54
|
+
|
|
55
|
+
return data if isinstance(data, (int, float, bool, str)) else str(data)
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def set_data_normalized(span, key, value, unpack=True):
|
|
59
|
+
# type: (Span, str, Any, bool) -> None
|
|
60
|
+
normalized = _normalize_data(value, unpack=unpack)
|
|
61
|
+
if isinstance(normalized, (int, float, bool, str)):
|
|
62
|
+
span.set_data(key, normalized)
|
|
63
|
+
else:
|
|
64
|
+
span.set_data(key, json.dumps(normalized))
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
def normalize_message_role(role):
|
|
68
|
+
# type: (str) -> str
|
|
69
|
+
"""
|
|
70
|
+
Normalize a message role to one of the 4 allowed gen_ai role values.
|
|
71
|
+
Maps "ai" -> "assistant" and keeps other standard roles unchanged.
|
|
72
|
+
"""
|
|
73
|
+
return GEN_AI_MESSAGE_ROLE_MAPPING.get(role, role)
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
def normalize_message_roles(messages):
|
|
77
|
+
# type: (list[dict[str, Any]]) -> list[dict[str, Any]]
|
|
78
|
+
"""
|
|
79
|
+
Normalize roles in a list of messages to use standard gen_ai role values.
|
|
80
|
+
Creates a deep copy to avoid modifying the original messages.
|
|
81
|
+
"""
|
|
82
|
+
normalized_messages = []
|
|
83
|
+
for message in messages:
|
|
84
|
+
if not isinstance(message, dict):
|
|
85
|
+
normalized_messages.append(message)
|
|
86
|
+
continue
|
|
87
|
+
normalized_message = message.copy()
|
|
88
|
+
if "role" in message:
|
|
89
|
+
normalized_message["role"] = normalize_message_role(message["role"])
|
|
90
|
+
normalized_messages.append(normalized_message)
|
|
91
|
+
|
|
92
|
+
return normalized_messages
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
def get_start_span_function():
|
|
96
|
+
# type: () -> Callable[..., Any]
|
|
97
|
+
current_span = sentry_sdk.get_current_span()
|
|
98
|
+
transaction_exists = (
|
|
99
|
+
current_span is not None and current_span.containing_transaction is not None
|
|
100
|
+
)
|
|
101
|
+
return sentry_sdk.start_span if transaction_exists else sentry_sdk.start_transaction
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
def _find_truncation_index(messages, max_bytes):
|
|
105
|
+
# type: (List[Dict[str, Any]], int) -> int
|
|
106
|
+
"""
|
|
107
|
+
Find the index of the first message that would exceed the max bytes limit.
|
|
108
|
+
Compute the individual message sizes, and return the index of the first message from the back
|
|
109
|
+
of the list that would exceed the max bytes limit.
|
|
110
|
+
"""
|
|
111
|
+
running_sum = 0
|
|
112
|
+
for idx in range(len(messages) - 1, -1, -1):
|
|
113
|
+
size = len(json.dumps(messages[idx], separators=(",", ":")).encode("utf-8"))
|
|
114
|
+
running_sum += size
|
|
115
|
+
if running_sum > max_bytes:
|
|
116
|
+
return idx + 1
|
|
117
|
+
|
|
118
|
+
return 0
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
def truncate_messages_by_size(messages, max_bytes=MAX_GEN_AI_MESSAGE_BYTES):
|
|
122
|
+
# type: (List[Dict[str, Any]], int) -> Tuple[List[Dict[str, Any]], int]
|
|
123
|
+
serialized_json = json.dumps(messages, separators=(",", ":"))
|
|
124
|
+
current_size = len(serialized_json.encode("utf-8"))
|
|
125
|
+
|
|
126
|
+
if current_size <= max_bytes:
|
|
127
|
+
return messages, 0
|
|
128
|
+
|
|
129
|
+
truncation_index = _find_truncation_index(messages, max_bytes)
|
|
130
|
+
return messages[truncation_index:], truncation_index
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
def truncate_and_annotate_messages(
|
|
134
|
+
messages, span, scope, max_bytes=MAX_GEN_AI_MESSAGE_BYTES
|
|
135
|
+
):
|
|
136
|
+
# type: (Optional[List[Dict[str, Any]]], Any, Any, int) -> Optional[List[Dict[str, Any]]]
|
|
137
|
+
if not messages:
|
|
138
|
+
return None
|
|
139
|
+
|
|
140
|
+
truncated_messages, removed_count = truncate_messages_by_size(messages, max_bytes)
|
|
141
|
+
if removed_count > 0:
|
|
142
|
+
scope._gen_ai_original_message_count[span.span_id] = len(messages)
|
|
143
|
+
|
|
144
|
+
return truncated_messages
|