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
|
@@ -1,14 +1,21 @@
|
|
|
1
|
-
import sys
|
|
2
1
|
import weakref
|
|
2
|
+
import contextlib
|
|
3
3
|
from inspect import iscoroutinefunction
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
import sentry_sdk
|
|
6
|
+
from sentry_sdk.api import continue_trace
|
|
7
|
+
from sentry_sdk.consts import OP
|
|
8
|
+
from sentry_sdk.scope import should_send_default_pii
|
|
9
|
+
from sentry_sdk.tracing import TransactionSource
|
|
6
10
|
from sentry_sdk.utils import (
|
|
11
|
+
HAS_REAL_CONTEXTVARS,
|
|
12
|
+
CONTEXTVARS_ERROR_MESSAGE,
|
|
13
|
+
ensure_integration_enabled,
|
|
7
14
|
event_from_exception,
|
|
8
15
|
capture_internal_exceptions,
|
|
9
16
|
transaction_from_function,
|
|
10
17
|
)
|
|
11
|
-
from sentry_sdk.integrations import Integration
|
|
18
|
+
from sentry_sdk.integrations import _check_minimum_version, Integration, DidNotEnable
|
|
12
19
|
from sentry_sdk.integrations._wsgi_common import (
|
|
13
20
|
RequestExtractor,
|
|
14
21
|
_filter_headers,
|
|
@@ -16,37 +23,42 @@ from sentry_sdk.integrations._wsgi_common import (
|
|
|
16
23
|
)
|
|
17
24
|
from sentry_sdk.integrations.logging import ignore_logger
|
|
18
25
|
|
|
19
|
-
|
|
20
|
-
from tornado
|
|
26
|
+
try:
|
|
27
|
+
from tornado import version_info as TORNADO_VERSION
|
|
28
|
+
from tornado.web import RequestHandler, HTTPError
|
|
29
|
+
from tornado.gen import coroutine
|
|
30
|
+
except ImportError:
|
|
31
|
+
raise DidNotEnable("Tornado not installed")
|
|
21
32
|
|
|
22
|
-
|
|
33
|
+
from typing import TYPE_CHECKING
|
|
34
|
+
|
|
35
|
+
if TYPE_CHECKING:
|
|
23
36
|
from typing import Any
|
|
24
|
-
from typing import List
|
|
25
37
|
from typing import Optional
|
|
26
38
|
from typing import Dict
|
|
27
39
|
from typing import Callable
|
|
40
|
+
from typing import Generator
|
|
41
|
+
|
|
42
|
+
from sentry_sdk._types import Event, EventProcessor
|
|
28
43
|
|
|
29
44
|
|
|
30
45
|
class TornadoIntegration(Integration):
|
|
31
46
|
identifier = "tornado"
|
|
47
|
+
origin = f"auto.http.{identifier}"
|
|
32
48
|
|
|
33
49
|
@staticmethod
|
|
34
50
|
def setup_once():
|
|
35
51
|
# type: () -> None
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
tornado_version = getattr(tornado, "version_info", None)
|
|
39
|
-
if tornado_version is None or tornado_version < (5, 0):
|
|
40
|
-
raise RuntimeError("Tornado 5+ required")
|
|
52
|
+
_check_minimum_version(TornadoIntegration, TORNADO_VERSION)
|
|
41
53
|
|
|
42
|
-
if
|
|
54
|
+
if not HAS_REAL_CONTEXTVARS:
|
|
43
55
|
# Tornado is async. We better have contextvars or we're going to leak
|
|
44
56
|
# state between requests.
|
|
45
|
-
raise
|
|
46
|
-
"The tornado integration for Sentry requires Python 3.7+"
|
|
57
|
+
raise DidNotEnable(
|
|
58
|
+
"The tornado integration for Sentry requires Python 3.7+ or the aiocontextvars package"
|
|
59
|
+
+ CONTEXTVARS_ERROR_MESSAGE
|
|
47
60
|
)
|
|
48
61
|
|
|
49
|
-
ignore_logger("tornado.application")
|
|
50
62
|
ignore_logger("tornado.access")
|
|
51
63
|
|
|
52
64
|
old_execute = RequestHandler._execute
|
|
@@ -57,33 +69,16 @@ class TornadoIntegration(Integration):
|
|
|
57
69
|
# Starting Tornado 6 RequestHandler._execute method is a standard Python coroutine (async/await)
|
|
58
70
|
# In that case our method should be a coroutine function too
|
|
59
71
|
async def sentry_execute_request_handler(self, *args, **kwargs):
|
|
60
|
-
# type: (
|
|
61
|
-
|
|
62
|
-
integration = hub.get_integration(TornadoIntegration)
|
|
63
|
-
if integration is None:
|
|
64
|
-
return await old_execute(self, *args, **kwargs)
|
|
65
|
-
|
|
66
|
-
weak_handler = weakref.ref(self)
|
|
67
|
-
|
|
68
|
-
with Hub(hub) as hub:
|
|
69
|
-
with hub.configure_scope() as scope:
|
|
70
|
-
scope.add_event_processor(_make_event_processor(weak_handler))
|
|
72
|
+
# type: (RequestHandler, *Any, **Any) -> Any
|
|
73
|
+
with _handle_request_impl(self):
|
|
71
74
|
return await old_execute(self, *args, **kwargs)
|
|
72
75
|
|
|
73
76
|
else:
|
|
74
77
|
|
|
75
78
|
@coroutine # type: ignore
|
|
76
79
|
def sentry_execute_request_handler(self, *args, **kwargs):
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
if integration is None:
|
|
80
|
-
return old_execute(self, *args, **kwargs)
|
|
81
|
-
|
|
82
|
-
weak_handler = weakref.ref(self)
|
|
83
|
-
|
|
84
|
-
with Hub(hub) as hub:
|
|
85
|
-
with hub.configure_scope() as scope:
|
|
86
|
-
scope.add_event_processor(_make_event_processor(weak_handler))
|
|
80
|
+
# type: (RequestHandler, *Any, **Any) -> Any
|
|
81
|
+
with _handle_request_impl(self):
|
|
87
82
|
result = yield from old_execute(self, *args, **kwargs)
|
|
88
83
|
return result
|
|
89
84
|
|
|
@@ -99,27 +94,60 @@ class TornadoIntegration(Integration):
|
|
|
99
94
|
RequestHandler.log_exception = sentry_log_exception
|
|
100
95
|
|
|
101
96
|
|
|
97
|
+
@contextlib.contextmanager
|
|
98
|
+
def _handle_request_impl(self):
|
|
99
|
+
# type: (RequestHandler) -> Generator[None, None, None]
|
|
100
|
+
integration = sentry_sdk.get_client().get_integration(TornadoIntegration)
|
|
101
|
+
|
|
102
|
+
if integration is None:
|
|
103
|
+
yield
|
|
104
|
+
|
|
105
|
+
weak_handler = weakref.ref(self)
|
|
106
|
+
|
|
107
|
+
with sentry_sdk.isolation_scope() as scope:
|
|
108
|
+
headers = self.request.headers
|
|
109
|
+
|
|
110
|
+
scope.clear_breadcrumbs()
|
|
111
|
+
processor = _make_event_processor(weak_handler)
|
|
112
|
+
scope.add_event_processor(processor)
|
|
113
|
+
|
|
114
|
+
transaction = continue_trace(
|
|
115
|
+
headers,
|
|
116
|
+
op=OP.HTTP_SERVER,
|
|
117
|
+
# Like with all other integrations, this is our
|
|
118
|
+
# fallback transaction in case there is no route.
|
|
119
|
+
# sentry_urldispatcher_resolve is responsible for
|
|
120
|
+
# setting a transaction name later.
|
|
121
|
+
name="generic Tornado request",
|
|
122
|
+
source=TransactionSource.ROUTE,
|
|
123
|
+
origin=TornadoIntegration.origin,
|
|
124
|
+
)
|
|
125
|
+
|
|
126
|
+
with sentry_sdk.start_transaction(
|
|
127
|
+
transaction, custom_sampling_context={"tornado_request": self.request}
|
|
128
|
+
):
|
|
129
|
+
yield
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
@ensure_integration_enabled(TornadoIntegration)
|
|
102
133
|
def _capture_exception(ty, value, tb):
|
|
103
134
|
# type: (type, BaseException, Any) -> None
|
|
104
|
-
hub = Hub.current
|
|
105
|
-
if hub.get_integration(TornadoIntegration) is None:
|
|
106
|
-
return
|
|
107
135
|
if isinstance(value, HTTPError):
|
|
108
136
|
return
|
|
109
137
|
|
|
110
138
|
event, hint = event_from_exception(
|
|
111
139
|
(ty, value, tb),
|
|
112
|
-
client_options=
|
|
140
|
+
client_options=sentry_sdk.get_client().options,
|
|
113
141
|
mechanism={"type": "tornado", "handled": False},
|
|
114
142
|
)
|
|
115
143
|
|
|
116
|
-
|
|
144
|
+
sentry_sdk.capture_event(event, hint=hint)
|
|
117
145
|
|
|
118
146
|
|
|
119
147
|
def _make_event_processor(weak_handler):
|
|
120
|
-
# type: (Callable[[], RequestHandler]) ->
|
|
148
|
+
# type: (Callable[[], RequestHandler]) -> EventProcessor
|
|
121
149
|
def tornado_processor(event, hint):
|
|
122
|
-
# type: (
|
|
150
|
+
# type: (Event, dict[str, Any]) -> Event
|
|
123
151
|
handler = weak_handler()
|
|
124
152
|
if handler is None:
|
|
125
153
|
return event
|
|
@@ -128,7 +156,8 @@ def _make_event_processor(weak_handler):
|
|
|
128
156
|
|
|
129
157
|
with capture_internal_exceptions():
|
|
130
158
|
method = getattr(handler, handler.request.method.lower())
|
|
131
|
-
event["transaction"] = transaction_from_function(method)
|
|
159
|
+
event["transaction"] = transaction_from_function(method) or ""
|
|
160
|
+
event["transaction_info"] = {"source": TransactionSource.COMPONENT}
|
|
132
161
|
|
|
133
162
|
with capture_internal_exceptions():
|
|
134
163
|
extractor = TornadoRequestExtractor(request)
|
|
@@ -148,8 +177,8 @@ def _make_event_processor(weak_handler):
|
|
|
148
177
|
request_info["headers"] = _filter_headers(dict(request.headers))
|
|
149
178
|
|
|
150
179
|
with capture_internal_exceptions():
|
|
151
|
-
if handler.current_user and
|
|
152
|
-
event.setdefault("user", {})
|
|
180
|
+
if handler.current_user and should_send_default_pii():
|
|
181
|
+
event.setdefault("user", {}).setdefault("is_authenticated", True)
|
|
153
182
|
|
|
154
183
|
return event
|
|
155
184
|
|
|
@@ -164,7 +193,7 @@ class TornadoRequestExtractor(RequestExtractor):
|
|
|
164
193
|
return len(self.request.body)
|
|
165
194
|
|
|
166
195
|
def cookies(self):
|
|
167
|
-
# type: () -> Dict
|
|
196
|
+
# type: () -> Dict[str, str]
|
|
168
197
|
return {k: v.value for k, v in self.request.cookies.items()}
|
|
169
198
|
|
|
170
199
|
def raw_data(self):
|
|
@@ -172,17 +201,20 @@ class TornadoRequestExtractor(RequestExtractor):
|
|
|
172
201
|
return self.request.body
|
|
173
202
|
|
|
174
203
|
def form(self):
|
|
175
|
-
# type: () ->
|
|
176
|
-
|
|
177
|
-
|
|
204
|
+
# type: () -> Dict[str, Any]
|
|
205
|
+
return {
|
|
206
|
+
k: [v.decode("latin1", "replace") for v in vs]
|
|
207
|
+
for k, vs in self.request.body_arguments.items()
|
|
208
|
+
}
|
|
178
209
|
|
|
179
210
|
def is_json(self):
|
|
180
211
|
# type: () -> bool
|
|
181
212
|
return _is_json_content_type(self.request.headers.get("content-type"))
|
|
182
213
|
|
|
183
214
|
def files(self):
|
|
184
|
-
# type: () -> Dict
|
|
215
|
+
# type: () -> Dict[str, Any]
|
|
185
216
|
return {k: v[0] for k, v in self.request.files.items() if v}
|
|
186
217
|
|
|
187
218
|
def size_of_file(self, file):
|
|
219
|
+
# type: (Any) -> int
|
|
188
220
|
return len(file.body or ())
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import sentry_sdk
|
|
2
|
+
from sentry_sdk.integrations import Integration
|
|
3
|
+
from sentry_sdk.integrations.wsgi import SentryWsgiMiddleware
|
|
4
|
+
from sentry_sdk.utils import ensure_integration_enabled, event_from_exception
|
|
5
|
+
|
|
6
|
+
from trytond.exceptions import TrytonException # type: ignore
|
|
7
|
+
from trytond.wsgi import app # type: ignore
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
# TODO: trytond-worker, trytond-cron and trytond-admin intergations
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class TrytondWSGIIntegration(Integration):
|
|
14
|
+
identifier = "trytond_wsgi"
|
|
15
|
+
origin = f"auto.http.{identifier}"
|
|
16
|
+
|
|
17
|
+
def __init__(self): # type: () -> None
|
|
18
|
+
pass
|
|
19
|
+
|
|
20
|
+
@staticmethod
|
|
21
|
+
def setup_once(): # type: () -> None
|
|
22
|
+
app.wsgi_app = SentryWsgiMiddleware(
|
|
23
|
+
app.wsgi_app,
|
|
24
|
+
span_origin=TrytondWSGIIntegration.origin,
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
@ensure_integration_enabled(TrytondWSGIIntegration)
|
|
28
|
+
def error_handler(e): # type: (Exception) -> None
|
|
29
|
+
if isinstance(e, TrytonException):
|
|
30
|
+
return
|
|
31
|
+
else:
|
|
32
|
+
client = sentry_sdk.get_client()
|
|
33
|
+
event, hint = event_from_exception(
|
|
34
|
+
e,
|
|
35
|
+
client_options=client.options,
|
|
36
|
+
mechanism={"type": "trytond", "handled": False},
|
|
37
|
+
)
|
|
38
|
+
sentry_sdk.capture_event(event, hint=hint)
|
|
39
|
+
|
|
40
|
+
# Expected error handlers signature was changed
|
|
41
|
+
# when the error_handler decorator was introduced
|
|
42
|
+
# in Tryton-5.4
|
|
43
|
+
if hasattr(app, "error_handler"):
|
|
44
|
+
|
|
45
|
+
@app.error_handler
|
|
46
|
+
def _(app, request, e): # type: ignore
|
|
47
|
+
error_handler(e)
|
|
48
|
+
|
|
49
|
+
else:
|
|
50
|
+
app.error_handlers.append(error_handler)
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import sentry_sdk
|
|
2
|
+
from sentry_sdk.utils import (
|
|
3
|
+
capture_internal_exceptions,
|
|
4
|
+
event_from_exception,
|
|
5
|
+
)
|
|
6
|
+
from sentry_sdk.integrations import Integration, DidNotEnable
|
|
7
|
+
|
|
8
|
+
from typing import TYPE_CHECKING
|
|
9
|
+
|
|
10
|
+
if TYPE_CHECKING:
|
|
11
|
+
from typing import Callable
|
|
12
|
+
from typing import Any
|
|
13
|
+
from typing import Type
|
|
14
|
+
from typing import Optional
|
|
15
|
+
|
|
16
|
+
from types import TracebackType
|
|
17
|
+
|
|
18
|
+
Excepthook = Callable[
|
|
19
|
+
[Type[BaseException], BaseException, Optional[TracebackType]],
|
|
20
|
+
Any,
|
|
21
|
+
]
|
|
22
|
+
|
|
23
|
+
try:
|
|
24
|
+
import typer
|
|
25
|
+
except ImportError:
|
|
26
|
+
raise DidNotEnable("Typer not installed")
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
class TyperIntegration(Integration):
|
|
30
|
+
identifier = "typer"
|
|
31
|
+
|
|
32
|
+
@staticmethod
|
|
33
|
+
def setup_once():
|
|
34
|
+
# type: () -> None
|
|
35
|
+
typer.main.except_hook = _make_excepthook(typer.main.except_hook) # type: ignore
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def _make_excepthook(old_excepthook):
|
|
39
|
+
# type: (Excepthook) -> Excepthook
|
|
40
|
+
def sentry_sdk_excepthook(type_, value, traceback):
|
|
41
|
+
# type: (Type[BaseException], BaseException, Optional[TracebackType]) -> None
|
|
42
|
+
integration = sentry_sdk.get_client().get_integration(TyperIntegration)
|
|
43
|
+
|
|
44
|
+
# Note: If we replace this with ensure_integration_enabled then
|
|
45
|
+
# we break the exceptiongroup backport;
|
|
46
|
+
# See: https://github.com/getsentry/sentry-python/issues/3097
|
|
47
|
+
if integration is None:
|
|
48
|
+
return old_excepthook(type_, value, traceback)
|
|
49
|
+
|
|
50
|
+
with capture_internal_exceptions():
|
|
51
|
+
event, hint = event_from_exception(
|
|
52
|
+
(type_, value, traceback),
|
|
53
|
+
client_options=sentry_sdk.get_client().options,
|
|
54
|
+
mechanism={"type": "typer", "handled": False},
|
|
55
|
+
)
|
|
56
|
+
sentry_sdk.capture_event(event, hint=hint)
|
|
57
|
+
|
|
58
|
+
return old_excepthook(type_, value, traceback)
|
|
59
|
+
|
|
60
|
+
return sentry_sdk_excepthook
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
from functools import wraps
|
|
2
|
+
from typing import Any
|
|
3
|
+
|
|
4
|
+
from sentry_sdk.feature_flags import add_feature_flag
|
|
5
|
+
from sentry_sdk.integrations import Integration, DidNotEnable
|
|
6
|
+
|
|
7
|
+
try:
|
|
8
|
+
from UnleashClient import UnleashClient
|
|
9
|
+
except ImportError:
|
|
10
|
+
raise DidNotEnable("UnleashClient is not installed")
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class UnleashIntegration(Integration):
|
|
14
|
+
identifier = "unleash"
|
|
15
|
+
|
|
16
|
+
@staticmethod
|
|
17
|
+
def setup_once():
|
|
18
|
+
# type: () -> None
|
|
19
|
+
# Wrap and patch evaluation methods (class methods)
|
|
20
|
+
old_is_enabled = UnleashClient.is_enabled
|
|
21
|
+
|
|
22
|
+
@wraps(old_is_enabled)
|
|
23
|
+
def sentry_is_enabled(self, feature, *args, **kwargs):
|
|
24
|
+
# type: (UnleashClient, str, *Any, **Any) -> Any
|
|
25
|
+
enabled = old_is_enabled(self, feature, *args, **kwargs)
|
|
26
|
+
|
|
27
|
+
# We have no way of knowing what type of unleash feature this is, so we have to treat
|
|
28
|
+
# it as a boolean / toggle feature.
|
|
29
|
+
add_feature_flag(feature, enabled)
|
|
30
|
+
|
|
31
|
+
return enabled
|
|
32
|
+
|
|
33
|
+
UnleashClient.is_enabled = sentry_is_enabled # type: ignore
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import sys
|
|
2
|
+
|
|
3
|
+
import sentry_sdk
|
|
4
|
+
from sentry_sdk.utils import (
|
|
5
|
+
capture_internal_exceptions,
|
|
6
|
+
event_from_exception,
|
|
7
|
+
)
|
|
8
|
+
from sentry_sdk.integrations import Integration
|
|
9
|
+
|
|
10
|
+
from typing import TYPE_CHECKING
|
|
11
|
+
|
|
12
|
+
if TYPE_CHECKING:
|
|
13
|
+
from typing import Callable
|
|
14
|
+
from typing import Any
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class UnraisablehookIntegration(Integration):
|
|
18
|
+
identifier = "unraisablehook"
|
|
19
|
+
|
|
20
|
+
@staticmethod
|
|
21
|
+
def setup_once():
|
|
22
|
+
# type: () -> None
|
|
23
|
+
sys.unraisablehook = _make_unraisable(sys.unraisablehook)
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def _make_unraisable(old_unraisablehook):
|
|
27
|
+
# type: (Callable[[sys.UnraisableHookArgs], Any]) -> Callable[[sys.UnraisableHookArgs], Any]
|
|
28
|
+
def sentry_sdk_unraisablehook(unraisable):
|
|
29
|
+
# type: (sys.UnraisableHookArgs) -> None
|
|
30
|
+
integration = sentry_sdk.get_client().get_integration(UnraisablehookIntegration)
|
|
31
|
+
|
|
32
|
+
# Note: If we replace this with ensure_integration_enabled then
|
|
33
|
+
# we break the exceptiongroup backport;
|
|
34
|
+
# See: https://github.com/getsentry/sentry-python/issues/3097
|
|
35
|
+
if integration is None:
|
|
36
|
+
return old_unraisablehook(unraisable)
|
|
37
|
+
|
|
38
|
+
if unraisable.exc_value and unraisable.exc_traceback:
|
|
39
|
+
with capture_internal_exceptions():
|
|
40
|
+
event, hint = event_from_exception(
|
|
41
|
+
(
|
|
42
|
+
unraisable.exc_type,
|
|
43
|
+
unraisable.exc_value,
|
|
44
|
+
unraisable.exc_traceback,
|
|
45
|
+
),
|
|
46
|
+
client_options=sentry_sdk.get_client().options,
|
|
47
|
+
mechanism={"type": "unraisablehook", "handled": False},
|
|
48
|
+
)
|
|
49
|
+
sentry_sdk.capture_event(event, hint=hint)
|
|
50
|
+
|
|
51
|
+
return old_unraisablehook(unraisable)
|
|
52
|
+
|
|
53
|
+
return sentry_sdk_unraisablehook
|