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
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import sentry_sdk
|
|
4
|
+
from sentry_sdk.consts import SPANDATA
|
|
5
|
+
from sentry_sdk.integrations import DidNotEnable
|
|
6
|
+
from sentry_sdk.scope import should_send_default_pii
|
|
7
|
+
from sentry_sdk.utils import event_from_exception, safe_serialize
|
|
8
|
+
|
|
9
|
+
from typing import TYPE_CHECKING
|
|
10
|
+
|
|
11
|
+
if TYPE_CHECKING:
|
|
12
|
+
from typing import Any
|
|
13
|
+
from agents import Usage
|
|
14
|
+
|
|
15
|
+
try:
|
|
16
|
+
import agents
|
|
17
|
+
|
|
18
|
+
except ImportError:
|
|
19
|
+
raise DidNotEnable("OpenAI Agents not installed")
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def _capture_exception(exc: Any) -> None:
|
|
23
|
+
event, hint = event_from_exception(
|
|
24
|
+
exc,
|
|
25
|
+
client_options=sentry_sdk.get_client().options,
|
|
26
|
+
mechanism={"type": "openai_agents", "handled": False},
|
|
27
|
+
)
|
|
28
|
+
sentry_sdk.capture_event(event, hint=hint)
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def _set_agent_data(span: sentry_sdk.tracing.Span, agent: agents.Agent) -> None:
|
|
32
|
+
span.set_attribute(
|
|
33
|
+
SPANDATA.GEN_AI_SYSTEM, "openai"
|
|
34
|
+
) # See footnote for https://opentelemetry.io/docs/specs/semconv/registry/attributes/gen-ai/#gen-ai-system for explanation why.
|
|
35
|
+
|
|
36
|
+
span.set_attribute(SPANDATA.GEN_AI_AGENT_NAME, agent.name)
|
|
37
|
+
|
|
38
|
+
if agent.model_settings.max_tokens:
|
|
39
|
+
span.set_attribute(
|
|
40
|
+
SPANDATA.GEN_AI_REQUEST_MAX_TOKENS, agent.model_settings.max_tokens
|
|
41
|
+
)
|
|
42
|
+
|
|
43
|
+
if agent.model:
|
|
44
|
+
model_name = agent.model.model if hasattr(agent.model, "model") else agent.model
|
|
45
|
+
span.set_attribute(SPANDATA.GEN_AI_REQUEST_MODEL, model_name)
|
|
46
|
+
|
|
47
|
+
if agent.model_settings.presence_penalty:
|
|
48
|
+
span.set_attribute(
|
|
49
|
+
SPANDATA.GEN_AI_REQUEST_PRESENCE_PENALTY,
|
|
50
|
+
agent.model_settings.presence_penalty,
|
|
51
|
+
)
|
|
52
|
+
|
|
53
|
+
if agent.model_settings.temperature:
|
|
54
|
+
span.set_attribute(
|
|
55
|
+
SPANDATA.GEN_AI_REQUEST_TEMPERATURE, agent.model_settings.temperature
|
|
56
|
+
)
|
|
57
|
+
|
|
58
|
+
if agent.model_settings.top_p:
|
|
59
|
+
span.set_attribute(SPANDATA.GEN_AI_REQUEST_TOP_P, agent.model_settings.top_p)
|
|
60
|
+
|
|
61
|
+
if agent.model_settings.frequency_penalty:
|
|
62
|
+
span.set_attribute(
|
|
63
|
+
SPANDATA.GEN_AI_REQUEST_FREQUENCY_PENALTY,
|
|
64
|
+
agent.model_settings.frequency_penalty,
|
|
65
|
+
)
|
|
66
|
+
|
|
67
|
+
if len(agent.tools) > 0:
|
|
68
|
+
span.set_attribute(
|
|
69
|
+
SPANDATA.GEN_AI_REQUEST_AVAILABLE_TOOLS,
|
|
70
|
+
safe_serialize([vars(tool) for tool in agent.tools]),
|
|
71
|
+
)
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
def _set_usage_data(span: sentry_sdk.tracing.Span, usage: Usage) -> None:
|
|
75
|
+
span.set_attribute(SPANDATA.GEN_AI_USAGE_INPUT_TOKENS, usage.input_tokens)
|
|
76
|
+
span.set_attribute(
|
|
77
|
+
SPANDATA.GEN_AI_USAGE_INPUT_TOKENS_CACHED,
|
|
78
|
+
usage.input_tokens_details.cached_tokens,
|
|
79
|
+
)
|
|
80
|
+
span.set_attribute(SPANDATA.GEN_AI_USAGE_OUTPUT_TOKENS, usage.output_tokens)
|
|
81
|
+
span.set_attribute(
|
|
82
|
+
SPANDATA.GEN_AI_USAGE_OUTPUT_TOKENS_REASONING,
|
|
83
|
+
usage.output_tokens_details.reasoning_tokens,
|
|
84
|
+
)
|
|
85
|
+
span.set_attribute(SPANDATA.GEN_AI_USAGE_TOTAL_TOKENS, usage.total_tokens)
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
def _set_input_data(
|
|
89
|
+
span: sentry_sdk.tracing.Span, get_response_kwargs: dict[str, Any]
|
|
90
|
+
) -> None:
|
|
91
|
+
if not should_send_default_pii():
|
|
92
|
+
return
|
|
93
|
+
|
|
94
|
+
messages_by_role: dict[str, list[Any]] = {
|
|
95
|
+
"system": [],
|
|
96
|
+
"user": [],
|
|
97
|
+
"assistant": [],
|
|
98
|
+
"tool": [],
|
|
99
|
+
}
|
|
100
|
+
system_instructions = get_response_kwargs.get("system_instructions")
|
|
101
|
+
if system_instructions:
|
|
102
|
+
messages_by_role["system"].append({"type": "text", "text": system_instructions})
|
|
103
|
+
|
|
104
|
+
for message in get_response_kwargs.get("input", []):
|
|
105
|
+
if "role" in message:
|
|
106
|
+
messages_by_role[message.get("role")].append(
|
|
107
|
+
{"type": "text", "text": message.get("content")}
|
|
108
|
+
)
|
|
109
|
+
else:
|
|
110
|
+
if message.get("type") == "function_call":
|
|
111
|
+
messages_by_role["assistant"].append(message)
|
|
112
|
+
elif message.get("type") == "function_call_output":
|
|
113
|
+
messages_by_role["tool"].append(message)
|
|
114
|
+
|
|
115
|
+
request_messages = []
|
|
116
|
+
for role, messages in messages_by_role.items():
|
|
117
|
+
if len(messages) > 0:
|
|
118
|
+
request_messages.append({"role": role, "content": messages})
|
|
119
|
+
|
|
120
|
+
span.set_attribute(
|
|
121
|
+
SPANDATA.GEN_AI_REQUEST_MESSAGES, safe_serialize(request_messages)
|
|
122
|
+
)
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
def _set_output_data(span: sentry_sdk.tracing.Span, result: Any) -> None:
|
|
126
|
+
if not should_send_default_pii():
|
|
127
|
+
return
|
|
128
|
+
|
|
129
|
+
output_messages: dict[str, list[Any]] = {
|
|
130
|
+
"response": [],
|
|
131
|
+
"tool": [],
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
for output in result.output:
|
|
135
|
+
if output.type == "function_call":
|
|
136
|
+
output_messages["tool"].append(output.model_dump())
|
|
137
|
+
elif output.type == "message":
|
|
138
|
+
for output_message in output.content:
|
|
139
|
+
try:
|
|
140
|
+
output_messages["response"].append(output_message.text)
|
|
141
|
+
except AttributeError:
|
|
142
|
+
# Unknown output message type, just return the json
|
|
143
|
+
output_messages["response"].append(output_message.dict())
|
|
144
|
+
|
|
145
|
+
if len(output_messages["tool"]) > 0:
|
|
146
|
+
span.set_attribute(
|
|
147
|
+
SPANDATA.GEN_AI_RESPONSE_TOOL_CALLS, safe_serialize(output_messages["tool"])
|
|
148
|
+
)
|
|
149
|
+
|
|
150
|
+
if len(output_messages["response"]) > 0:
|
|
151
|
+
span.set_attribute(
|
|
152
|
+
SPANDATA.GEN_AI_RESPONSE_TEXT, safe_serialize(output_messages["response"])
|
|
153
|
+
)
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
from
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
from typing import TYPE_CHECKING, Any
|
|
2
3
|
|
|
3
4
|
from sentry_sdk.feature_flags import add_feature_flag
|
|
4
5
|
from sentry_sdk.integrations import DidNotEnable, Integration
|
|
@@ -8,7 +9,6 @@ try:
|
|
|
8
9
|
from openfeature.hook import Hook
|
|
9
10
|
|
|
10
11
|
if TYPE_CHECKING:
|
|
11
|
-
from openfeature.flag_evaluation import FlagEvaluationDetails
|
|
12
12
|
from openfeature.hook import HookContext, HookHints
|
|
13
13
|
except ImportError:
|
|
14
14
|
raise DidNotEnable("OpenFeature is not installed")
|
|
@@ -18,20 +18,24 @@ class OpenFeatureIntegration(Integration):
|
|
|
18
18
|
identifier = "openfeature"
|
|
19
19
|
|
|
20
20
|
@staticmethod
|
|
21
|
-
def setup_once():
|
|
22
|
-
# type: () -> None
|
|
21
|
+
def setup_once() -> None:
|
|
23
22
|
# Register the hook within the global openfeature hooks list.
|
|
24
23
|
api.add_hooks(hooks=[OpenFeatureHook()])
|
|
25
24
|
|
|
26
25
|
|
|
27
26
|
class OpenFeatureHook(Hook):
|
|
28
27
|
|
|
29
|
-
def after(
|
|
30
|
-
|
|
28
|
+
def after(
|
|
29
|
+
self,
|
|
30
|
+
hook_context: Any,
|
|
31
|
+
details: Any,
|
|
32
|
+
hints: Any,
|
|
33
|
+
) -> None:
|
|
31
34
|
if isinstance(details.value, bool):
|
|
32
35
|
add_feature_flag(details.flag_key, details.value)
|
|
33
36
|
|
|
34
|
-
def error(
|
|
35
|
-
|
|
37
|
+
def error(
|
|
38
|
+
self, hook_context: HookContext, exception: Exception, hints: HookHints
|
|
39
|
+
) -> None:
|
|
36
40
|
if isinstance(hook_context.default_value, bool):
|
|
37
41
|
add_feature_flag(hook_context.flag_key, hook_context.default_value)
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
1
2
|
import ast
|
|
2
3
|
|
|
3
4
|
import sentry_sdk
|
|
@@ -35,12 +36,10 @@ class PureEvalIntegration(Integration):
|
|
|
35
36
|
identifier = "pure_eval"
|
|
36
37
|
|
|
37
38
|
@staticmethod
|
|
38
|
-
def setup_once():
|
|
39
|
-
# type: () -> None
|
|
39
|
+
def setup_once() -> None:
|
|
40
40
|
|
|
41
41
|
@add_global_event_processor
|
|
42
|
-
def add_executing_info(event, hint):
|
|
43
|
-
# type: (Event, Optional[Hint]) -> Optional[Event]
|
|
42
|
+
def add_executing_info(event: Event, hint: Optional[Hint]) -> Optional[Event]:
|
|
44
43
|
if sentry_sdk.get_client().get_integration(PureEvalIntegration) is None:
|
|
45
44
|
return event
|
|
46
45
|
|
|
@@ -81,8 +80,7 @@ class PureEvalIntegration(Integration):
|
|
|
81
80
|
return event
|
|
82
81
|
|
|
83
82
|
|
|
84
|
-
def pure_eval_frame(frame):
|
|
85
|
-
# type: (FrameType) -> Dict[str, Any]
|
|
83
|
+
def pure_eval_frame(frame: FrameType) -> Dict[str, Any]:
|
|
86
84
|
source = executing.Source.for_frame(frame)
|
|
87
85
|
if not source.tree:
|
|
88
86
|
return {}
|
|
@@ -103,16 +101,14 @@ def pure_eval_frame(frame):
|
|
|
103
101
|
evaluator = pure_eval.Evaluator.from_frame(frame)
|
|
104
102
|
expressions = evaluator.interesting_expressions_grouped(scope)
|
|
105
103
|
|
|
106
|
-
def closeness(expression):
|
|
107
|
-
# type: (Tuple[List[Any], Any]) -> Tuple[int, int]
|
|
104
|
+
def closeness(expression: Tuple[List[Any], Any]) -> Tuple[int, int]:
|
|
108
105
|
# Prioritise expressions with a node closer to the statement executed
|
|
109
106
|
# without being after that statement
|
|
110
107
|
# A higher return value is better - the expression will appear
|
|
111
108
|
# earlier in the list of values and is less likely to be trimmed
|
|
112
109
|
nodes, _value = expression
|
|
113
110
|
|
|
114
|
-
def start(n):
|
|
115
|
-
# type: (ast.expr) -> Tuple[int, int]
|
|
111
|
+
def start(n: ast.expr) -> Tuple[int, int]:
|
|
116
112
|
return (n.lineno, n.col_offset)
|
|
117
113
|
|
|
118
114
|
nodes_before_stmt = [
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
1
2
|
import copy
|
|
2
3
|
|
|
3
4
|
import sentry_sdk
|
|
@@ -41,8 +42,7 @@ SAFE_COMMAND_ATTRIBUTES = [
|
|
|
41
42
|
]
|
|
42
43
|
|
|
43
44
|
|
|
44
|
-
def _strip_pii(command):
|
|
45
|
-
# type: (Dict[str, Any]) -> Dict[str, Any]
|
|
45
|
+
def _strip_pii(command: Dict[str, Any]) -> Dict[str, Any]:
|
|
46
46
|
for key in command:
|
|
47
47
|
is_safe_field = key in SAFE_COMMAND_ATTRIBUTES
|
|
48
48
|
if is_safe_field:
|
|
@@ -84,8 +84,7 @@ def _strip_pii(command):
|
|
|
84
84
|
return command
|
|
85
85
|
|
|
86
86
|
|
|
87
|
-
def _get_db_data(event):
|
|
88
|
-
# type: (Any) -> Dict[str, Any]
|
|
87
|
+
def _get_db_data(event: Any) -> Dict[str, Any]:
|
|
89
88
|
data = {}
|
|
90
89
|
|
|
91
90
|
data[SPANDATA.DB_SYSTEM] = "mongodb"
|
|
@@ -106,16 +105,16 @@ def _get_db_data(event):
|
|
|
106
105
|
|
|
107
106
|
|
|
108
107
|
class CommandTracer(monitoring.CommandListener):
|
|
109
|
-
def __init__(self):
|
|
110
|
-
|
|
111
|
-
self._ongoing_operations = {} # type: Dict[int, Span]
|
|
108
|
+
def __init__(self) -> None:
|
|
109
|
+
self._ongoing_operations: Dict[int, Span] = {}
|
|
112
110
|
|
|
113
|
-
def _operation_key(
|
|
114
|
-
|
|
111
|
+
def _operation_key(
|
|
112
|
+
self,
|
|
113
|
+
event: Union[CommandFailedEvent, CommandStartedEvent, CommandSucceededEvent],
|
|
114
|
+
) -> int:
|
|
115
115
|
return event.request_id
|
|
116
116
|
|
|
117
|
-
def started(self, event):
|
|
118
|
-
# type: (CommandStartedEvent) -> None
|
|
117
|
+
def started(self, event: CommandStartedEvent) -> None:
|
|
119
118
|
if sentry_sdk.get_client().get_integration(PyMongoIntegration) is None:
|
|
120
119
|
return
|
|
121
120
|
|
|
@@ -153,7 +152,7 @@ class CommandTracer(monitoring.CommandListener):
|
|
|
153
152
|
op=OP.DB,
|
|
154
153
|
name=query,
|
|
155
154
|
origin=PyMongoIntegration.origin,
|
|
156
|
-
|
|
155
|
+
only_as_child_span=True,
|
|
157
156
|
)
|
|
158
157
|
|
|
159
158
|
with capture_internal_exceptions():
|
|
@@ -172,8 +171,7 @@ class CommandTracer(monitoring.CommandListener):
|
|
|
172
171
|
|
|
173
172
|
self._ongoing_operations[self._operation_key(event)] = span.__enter__()
|
|
174
173
|
|
|
175
|
-
def failed(self, event):
|
|
176
|
-
# type: (CommandFailedEvent) -> None
|
|
174
|
+
def failed(self, event: CommandFailedEvent) -> None:
|
|
177
175
|
if sentry_sdk.get_client().get_integration(PyMongoIntegration) is None:
|
|
178
176
|
return
|
|
179
177
|
|
|
@@ -184,8 +182,7 @@ class CommandTracer(monitoring.CommandListener):
|
|
|
184
182
|
except KeyError:
|
|
185
183
|
return
|
|
186
184
|
|
|
187
|
-
def succeeded(self, event):
|
|
188
|
-
# type: (CommandSucceededEvent) -> None
|
|
185
|
+
def succeeded(self, event: CommandSucceededEvent) -> None:
|
|
189
186
|
if sentry_sdk.get_client().get_integration(PyMongoIntegration) is None:
|
|
190
187
|
return
|
|
191
188
|
|
|
@@ -202,6 +199,5 @@ class PyMongoIntegration(Integration):
|
|
|
202
199
|
origin = f"auto.db.{identifier}"
|
|
203
200
|
|
|
204
201
|
@staticmethod
|
|
205
|
-
def setup_once():
|
|
206
|
-
# type: () -> None
|
|
202
|
+
def setup_once() -> None:
|
|
207
203
|
monitoring.register(CommandTracer())
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
1
2
|
import functools
|
|
2
3
|
import os
|
|
3
4
|
import sys
|
|
@@ -40,8 +41,7 @@ if TYPE_CHECKING:
|
|
|
40
41
|
|
|
41
42
|
if getattr(Request, "authenticated_userid", None):
|
|
42
43
|
|
|
43
|
-
def authenticated_userid(request):
|
|
44
|
-
# type: (Request) -> Optional[Any]
|
|
44
|
+
def authenticated_userid(request: Request) -> Optional[Any]:
|
|
45
45
|
return request.authenticated_userid
|
|
46
46
|
|
|
47
47
|
else:
|
|
@@ -58,8 +58,7 @@ class PyramidIntegration(Integration):
|
|
|
58
58
|
|
|
59
59
|
transaction_style = ""
|
|
60
60
|
|
|
61
|
-
def __init__(self, transaction_style="route_name"):
|
|
62
|
-
# type: (str) -> None
|
|
61
|
+
def __init__(self, transaction_style: str = "route_name") -> None:
|
|
63
62
|
if transaction_style not in TRANSACTION_STYLE_VALUES:
|
|
64
63
|
raise ValueError(
|
|
65
64
|
"Invalid value for transaction_style: %s (must be in %s)"
|
|
@@ -68,15 +67,15 @@ class PyramidIntegration(Integration):
|
|
|
68
67
|
self.transaction_style = transaction_style
|
|
69
68
|
|
|
70
69
|
@staticmethod
|
|
71
|
-
def setup_once():
|
|
72
|
-
# type: () -> None
|
|
70
|
+
def setup_once() -> None:
|
|
73
71
|
from pyramid import router
|
|
74
72
|
|
|
75
73
|
old_call_view = router._call_view
|
|
76
74
|
|
|
77
75
|
@functools.wraps(old_call_view)
|
|
78
|
-
def sentry_patched_call_view(
|
|
79
|
-
|
|
76
|
+
def sentry_patched_call_view(
|
|
77
|
+
registry: Any, request: Request, *args: Any, **kwargs: Any
|
|
78
|
+
) -> Response:
|
|
80
79
|
integration = sentry_sdk.get_client().get_integration(PyramidIntegration)
|
|
81
80
|
if integration is None:
|
|
82
81
|
return old_call_view(registry, request, *args, **kwargs)
|
|
@@ -96,8 +95,9 @@ class PyramidIntegration(Integration):
|
|
|
96
95
|
if hasattr(Request, "invoke_exception_view"):
|
|
97
96
|
old_invoke_exception_view = Request.invoke_exception_view
|
|
98
97
|
|
|
99
|
-
def sentry_patched_invoke_exception_view(
|
|
100
|
-
|
|
98
|
+
def sentry_patched_invoke_exception_view(
|
|
99
|
+
self: Request, *args: Any, **kwargs: Any
|
|
100
|
+
) -> Any:
|
|
101
101
|
rv = old_invoke_exception_view(self, *args, **kwargs)
|
|
102
102
|
|
|
103
103
|
if (
|
|
@@ -116,10 +116,12 @@ class PyramidIntegration(Integration):
|
|
|
116
116
|
old_wsgi_call = router.Router.__call__
|
|
117
117
|
|
|
118
118
|
@ensure_integration_enabled(PyramidIntegration, old_wsgi_call)
|
|
119
|
-
def sentry_patched_wsgi_call(
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
119
|
+
def sentry_patched_wsgi_call(
|
|
120
|
+
self: Any, environ: Dict[str, str], start_response: Callable[..., Any]
|
|
121
|
+
) -> _ScopedResponse:
|
|
122
|
+
def sentry_patched_inner_wsgi_call(
|
|
123
|
+
environ: Dict[str, Any], start_response: Callable[..., Any]
|
|
124
|
+
) -> Any:
|
|
123
125
|
try:
|
|
124
126
|
return old_wsgi_call(self, environ, start_response)
|
|
125
127
|
except Exception:
|
|
@@ -137,8 +139,7 @@ class PyramidIntegration(Integration):
|
|
|
137
139
|
|
|
138
140
|
|
|
139
141
|
@ensure_integration_enabled(PyramidIntegration)
|
|
140
|
-
def _capture_exception(exc_info):
|
|
141
|
-
# type: (ExcInfo) -> None
|
|
142
|
+
def _capture_exception(exc_info: ExcInfo) -> None:
|
|
142
143
|
if exc_info[0] is None or issubclass(exc_info[0], HTTPException):
|
|
143
144
|
return
|
|
144
145
|
|
|
@@ -151,8 +152,9 @@ def _capture_exception(exc_info):
|
|
|
151
152
|
sentry_sdk.capture_event(event, hint=hint)
|
|
152
153
|
|
|
153
154
|
|
|
154
|
-
def _set_transaction_name_and_source(
|
|
155
|
-
|
|
155
|
+
def _set_transaction_name_and_source(
|
|
156
|
+
scope: sentry_sdk.Scope, transaction_style: str, request: Request
|
|
157
|
+
) -> None:
|
|
156
158
|
try:
|
|
157
159
|
name_for_style = {
|
|
158
160
|
"route_name": request.matched_route.name,
|
|
@@ -167,40 +169,33 @@ def _set_transaction_name_and_source(scope, transaction_style, request):
|
|
|
167
169
|
|
|
168
170
|
|
|
169
171
|
class PyramidRequestExtractor(RequestExtractor):
|
|
170
|
-
def url(self):
|
|
171
|
-
# type: () -> str
|
|
172
|
+
def url(self) -> str:
|
|
172
173
|
return self.request.path_url
|
|
173
174
|
|
|
174
|
-
def env(self):
|
|
175
|
-
# type: () -> Dict[str, str]
|
|
175
|
+
def env(self) -> Dict[str, str]:
|
|
176
176
|
return self.request.environ
|
|
177
177
|
|
|
178
|
-
def cookies(self):
|
|
179
|
-
# type: () -> RequestCookies
|
|
178
|
+
def cookies(self) -> RequestCookies:
|
|
180
179
|
return self.request.cookies
|
|
181
180
|
|
|
182
|
-
def raw_data(self):
|
|
183
|
-
# type: () -> str
|
|
181
|
+
def raw_data(self) -> str:
|
|
184
182
|
return self.request.text
|
|
185
183
|
|
|
186
|
-
def form(self):
|
|
187
|
-
# type: () -> Dict[str, str]
|
|
184
|
+
def form(self) -> Dict[str, str]:
|
|
188
185
|
return {
|
|
189
186
|
key: value
|
|
190
187
|
for key, value in self.request.POST.items()
|
|
191
188
|
if not getattr(value, "filename", None)
|
|
192
189
|
}
|
|
193
190
|
|
|
194
|
-
def files(self):
|
|
195
|
-
# type: () -> Dict[str, _FieldStorageWithFile]
|
|
191
|
+
def files(self) -> Dict[str, _FieldStorageWithFile]:
|
|
196
192
|
return {
|
|
197
193
|
key: value
|
|
198
194
|
for key, value in self.request.POST.items()
|
|
199
195
|
if getattr(value, "filename", None)
|
|
200
196
|
}
|
|
201
197
|
|
|
202
|
-
def size_of_file(self, postdata):
|
|
203
|
-
# type: (_FieldStorageWithFile) -> int
|
|
198
|
+
def size_of_file(self, postdata: _FieldStorageWithFile) -> int:
|
|
204
199
|
file = postdata.file
|
|
205
200
|
try:
|
|
206
201
|
return os.fstat(file.fileno()).st_size
|
|
@@ -208,10 +203,10 @@ class PyramidRequestExtractor(RequestExtractor):
|
|
|
208
203
|
return 0
|
|
209
204
|
|
|
210
205
|
|
|
211
|
-
def _make_event_processor(
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
206
|
+
def _make_event_processor(
|
|
207
|
+
weak_request: Callable[[], Request], integration: PyramidIntegration
|
|
208
|
+
) -> EventProcessor:
|
|
209
|
+
def pyramid_event_processor(event: Event, hint: Dict[str, Any]) -> Event:
|
|
215
210
|
request = weak_request()
|
|
216
211
|
if request is None:
|
|
217
212
|
return event
|
sentry_sdk/integrations/quart.py
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
1
2
|
import asyncio
|
|
2
3
|
import inspect
|
|
3
4
|
from functools import wraps
|
|
@@ -60,8 +61,7 @@ class QuartIntegration(Integration):
|
|
|
60
61
|
|
|
61
62
|
transaction_style = ""
|
|
62
63
|
|
|
63
|
-
def __init__(self, transaction_style="endpoint"):
|
|
64
|
-
# type: (str) -> None
|
|
64
|
+
def __init__(self, transaction_style: str = "endpoint") -> None:
|
|
65
65
|
if transaction_style not in TRANSACTION_STYLE_VALUES:
|
|
66
66
|
raise ValueError(
|
|
67
67
|
"Invalid value for transaction_style: %s (must be in %s)"
|
|
@@ -70,8 +70,7 @@ class QuartIntegration(Integration):
|
|
|
70
70
|
self.transaction_style = transaction_style
|
|
71
71
|
|
|
72
72
|
@staticmethod
|
|
73
|
-
def setup_once():
|
|
74
|
-
# type: () -> None
|
|
73
|
+
def setup_once() -> None:
|
|
75
74
|
|
|
76
75
|
request_started.connect(_request_websocket_started)
|
|
77
76
|
websocket_started.connect(_request_websocket_started)
|
|
@@ -83,12 +82,12 @@ class QuartIntegration(Integration):
|
|
|
83
82
|
patch_scaffold_route()
|
|
84
83
|
|
|
85
84
|
|
|
86
|
-
def patch_asgi_app():
|
|
87
|
-
# type: () -> None
|
|
85
|
+
def patch_asgi_app() -> None:
|
|
88
86
|
old_app = Quart.__call__
|
|
89
87
|
|
|
90
|
-
async def sentry_patched_asgi_app(
|
|
91
|
-
|
|
88
|
+
async def sentry_patched_asgi_app(
|
|
89
|
+
self: Any, scope: Any, receive: Any, send: Any
|
|
90
|
+
) -> Any:
|
|
92
91
|
if sentry_sdk.get_client().get_integration(QuartIntegration) is None:
|
|
93
92
|
return await old_app(self, scope, receive, send)
|
|
94
93
|
|
|
@@ -102,16 +101,13 @@ def patch_asgi_app():
|
|
|
102
101
|
Quart.__call__ = sentry_patched_asgi_app
|
|
103
102
|
|
|
104
103
|
|
|
105
|
-
def patch_scaffold_route():
|
|
106
|
-
# type: () -> None
|
|
104
|
+
def patch_scaffold_route() -> None:
|
|
107
105
|
old_route = Scaffold.route
|
|
108
106
|
|
|
109
|
-
def _sentry_route(*args, **kwargs):
|
|
110
|
-
# type: (*Any, **Any) -> Any
|
|
107
|
+
def _sentry_route(*args: Any, **kwargs: Any) -> Any:
|
|
111
108
|
old_decorator = old_route(*args, **kwargs)
|
|
112
109
|
|
|
113
|
-
def decorator(old_func):
|
|
114
|
-
# type: (Any) -> Any
|
|
110
|
+
def decorator(old_func: Any) -> Any:
|
|
115
111
|
|
|
116
112
|
if inspect.isfunction(old_func) and not asyncio.iscoroutinefunction(
|
|
117
113
|
old_func
|
|
@@ -119,8 +115,7 @@ def patch_scaffold_route():
|
|
|
119
115
|
|
|
120
116
|
@wraps(old_func)
|
|
121
117
|
@ensure_integration_enabled(QuartIntegration, old_func)
|
|
122
|
-
def _sentry_func(*args, **kwargs):
|
|
123
|
-
# type: (*Any, **Any) -> Any
|
|
118
|
+
def _sentry_func(*args: Any, **kwargs: Any) -> Any:
|
|
124
119
|
current_scope = sentry_sdk.get_current_scope()
|
|
125
120
|
if current_scope.root_span is not None:
|
|
126
121
|
current_scope.root_span.update_active_thread()
|
|
@@ -140,8 +135,9 @@ def patch_scaffold_route():
|
|
|
140
135
|
Scaffold.route = _sentry_route
|
|
141
136
|
|
|
142
137
|
|
|
143
|
-
def _set_transaction_name_and_source(
|
|
144
|
-
|
|
138
|
+
def _set_transaction_name_and_source(
|
|
139
|
+
scope: sentry_sdk.Scope, transaction_style: str, request: Request
|
|
140
|
+
) -> None:
|
|
145
141
|
|
|
146
142
|
try:
|
|
147
143
|
name_for_style = {
|
|
@@ -156,8 +152,7 @@ def _set_transaction_name_and_source(scope, transaction_style, request):
|
|
|
156
152
|
pass
|
|
157
153
|
|
|
158
154
|
|
|
159
|
-
async def _request_websocket_started(app, **kwargs):
|
|
160
|
-
# type: (Quart, **Any) -> None
|
|
155
|
+
async def _request_websocket_started(app: Quart, **kwargs: Any) -> None:
|
|
161
156
|
integration = sentry_sdk.get_client().get_integration(QuartIntegration)
|
|
162
157
|
if integration is None:
|
|
163
158
|
return
|
|
@@ -178,10 +173,10 @@ async def _request_websocket_started(app, **kwargs):
|
|
|
178
173
|
scope.add_event_processor(evt_processor)
|
|
179
174
|
|
|
180
175
|
|
|
181
|
-
def _make_request_event_processor(
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
176
|
+
def _make_request_event_processor(
|
|
177
|
+
app: Quart, request: Request, integration: QuartIntegration
|
|
178
|
+
) -> EventProcessor:
|
|
179
|
+
def inner(event: Event, hint: dict[str, Any]) -> Event:
|
|
185
180
|
# if the request is gone we are fine not logging the data from
|
|
186
181
|
# it. This might happen if the processor is pushed away to
|
|
187
182
|
# another thread.
|
|
@@ -207,8 +202,9 @@ def _make_request_event_processor(app, request, integration):
|
|
|
207
202
|
return inner
|
|
208
203
|
|
|
209
204
|
|
|
210
|
-
async def _capture_exception(
|
|
211
|
-
|
|
205
|
+
async def _capture_exception(
|
|
206
|
+
sender: Quart, exception: Union[ValueError, BaseException], **kwargs: Any
|
|
207
|
+
) -> None:
|
|
212
208
|
integration = sentry_sdk.get_client().get_integration(QuartIntegration)
|
|
213
209
|
if integration is None:
|
|
214
210
|
return
|
|
@@ -222,8 +218,7 @@ async def _capture_exception(sender, exception, **kwargs):
|
|
|
222
218
|
sentry_sdk.capture_event(event, hint=hint)
|
|
223
219
|
|
|
224
220
|
|
|
225
|
-
def _add_user_to_event(event):
|
|
226
|
-
# type: (Event) -> None
|
|
221
|
+
def _add_user_to_event(event: Event) -> None:
|
|
227
222
|
if quart_auth is None:
|
|
228
223
|
return
|
|
229
224
|
|