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.
Files changed (193) hide show
  1. sentry_sdk/__init__.py +48 -30
  2. sentry_sdk/_compat.py +74 -61
  3. sentry_sdk/_init_implementation.py +84 -0
  4. sentry_sdk/_log_batcher.py +172 -0
  5. sentry_sdk/_lru_cache.py +47 -0
  6. sentry_sdk/_metrics_batcher.py +167 -0
  7. sentry_sdk/_queue.py +289 -0
  8. sentry_sdk/_types.py +338 -0
  9. sentry_sdk/_werkzeug.py +98 -0
  10. sentry_sdk/ai/__init__.py +7 -0
  11. sentry_sdk/ai/monitoring.py +137 -0
  12. sentry_sdk/ai/utils.py +144 -0
  13. sentry_sdk/api.py +496 -80
  14. sentry_sdk/attachments.py +75 -0
  15. sentry_sdk/client.py +1023 -103
  16. sentry_sdk/consts.py +1438 -66
  17. sentry_sdk/crons/__init__.py +10 -0
  18. sentry_sdk/crons/api.py +62 -0
  19. sentry_sdk/crons/consts.py +4 -0
  20. sentry_sdk/crons/decorator.py +135 -0
  21. sentry_sdk/debug.py +15 -14
  22. sentry_sdk/envelope.py +369 -0
  23. sentry_sdk/feature_flags.py +71 -0
  24. sentry_sdk/hub.py +611 -280
  25. sentry_sdk/integrations/__init__.py +276 -49
  26. sentry_sdk/integrations/_asgi_common.py +108 -0
  27. sentry_sdk/integrations/_wsgi_common.py +180 -44
  28. sentry_sdk/integrations/aiohttp.py +291 -42
  29. sentry_sdk/integrations/anthropic.py +439 -0
  30. sentry_sdk/integrations/argv.py +9 -8
  31. sentry_sdk/integrations/ariadne.py +161 -0
  32. sentry_sdk/integrations/arq.py +247 -0
  33. sentry_sdk/integrations/asgi.py +341 -0
  34. sentry_sdk/integrations/asyncio.py +144 -0
  35. sentry_sdk/integrations/asyncpg.py +208 -0
  36. sentry_sdk/integrations/atexit.py +17 -10
  37. sentry_sdk/integrations/aws_lambda.py +377 -62
  38. sentry_sdk/integrations/beam.py +176 -0
  39. sentry_sdk/integrations/boto3.py +137 -0
  40. sentry_sdk/integrations/bottle.py +221 -0
  41. sentry_sdk/integrations/celery/__init__.py +529 -0
  42. sentry_sdk/integrations/celery/beat.py +293 -0
  43. sentry_sdk/integrations/celery/utils.py +43 -0
  44. sentry_sdk/integrations/chalice.py +134 -0
  45. sentry_sdk/integrations/clickhouse_driver.py +177 -0
  46. sentry_sdk/integrations/cloud_resource_context.py +280 -0
  47. sentry_sdk/integrations/cohere.py +274 -0
  48. sentry_sdk/integrations/dedupe.py +48 -14
  49. sentry_sdk/integrations/django/__init__.py +584 -191
  50. sentry_sdk/integrations/django/asgi.py +245 -0
  51. sentry_sdk/integrations/django/caching.py +204 -0
  52. sentry_sdk/integrations/django/middleware.py +187 -0
  53. sentry_sdk/integrations/django/signals_handlers.py +91 -0
  54. sentry_sdk/integrations/django/templates.py +79 -5
  55. sentry_sdk/integrations/django/transactions.py +49 -22
  56. sentry_sdk/integrations/django/views.py +96 -0
  57. sentry_sdk/integrations/dramatiq.py +226 -0
  58. sentry_sdk/integrations/excepthook.py +50 -13
  59. sentry_sdk/integrations/executing.py +67 -0
  60. sentry_sdk/integrations/falcon.py +272 -0
  61. sentry_sdk/integrations/fastapi.py +141 -0
  62. sentry_sdk/integrations/flask.py +142 -88
  63. sentry_sdk/integrations/gcp.py +239 -0
  64. sentry_sdk/integrations/gnu_backtrace.py +99 -0
  65. sentry_sdk/integrations/google_genai/__init__.py +301 -0
  66. sentry_sdk/integrations/google_genai/consts.py +16 -0
  67. sentry_sdk/integrations/google_genai/streaming.py +155 -0
  68. sentry_sdk/integrations/google_genai/utils.py +576 -0
  69. sentry_sdk/integrations/gql.py +162 -0
  70. sentry_sdk/integrations/graphene.py +151 -0
  71. sentry_sdk/integrations/grpc/__init__.py +168 -0
  72. sentry_sdk/integrations/grpc/aio/__init__.py +7 -0
  73. sentry_sdk/integrations/grpc/aio/client.py +95 -0
  74. sentry_sdk/integrations/grpc/aio/server.py +100 -0
  75. sentry_sdk/integrations/grpc/client.py +91 -0
  76. sentry_sdk/integrations/grpc/consts.py +1 -0
  77. sentry_sdk/integrations/grpc/server.py +66 -0
  78. sentry_sdk/integrations/httpx.py +178 -0
  79. sentry_sdk/integrations/huey.py +174 -0
  80. sentry_sdk/integrations/huggingface_hub.py +378 -0
  81. sentry_sdk/integrations/langchain.py +1132 -0
  82. sentry_sdk/integrations/langgraph.py +337 -0
  83. sentry_sdk/integrations/launchdarkly.py +61 -0
  84. sentry_sdk/integrations/litellm.py +287 -0
  85. sentry_sdk/integrations/litestar.py +315 -0
  86. sentry_sdk/integrations/logging.py +307 -96
  87. sentry_sdk/integrations/loguru.py +213 -0
  88. sentry_sdk/integrations/mcp.py +566 -0
  89. sentry_sdk/integrations/modules.py +14 -31
  90. sentry_sdk/integrations/openai.py +725 -0
  91. sentry_sdk/integrations/openai_agents/__init__.py +61 -0
  92. sentry_sdk/integrations/openai_agents/consts.py +1 -0
  93. sentry_sdk/integrations/openai_agents/patches/__init__.py +5 -0
  94. sentry_sdk/integrations/openai_agents/patches/agent_run.py +140 -0
  95. sentry_sdk/integrations/openai_agents/patches/error_tracing.py +77 -0
  96. sentry_sdk/integrations/openai_agents/patches/models.py +50 -0
  97. sentry_sdk/integrations/openai_agents/patches/runner.py +45 -0
  98. sentry_sdk/integrations/openai_agents/patches/tools.py +77 -0
  99. sentry_sdk/integrations/openai_agents/spans/__init__.py +5 -0
  100. sentry_sdk/integrations/openai_agents/spans/agent_workflow.py +21 -0
  101. sentry_sdk/integrations/openai_agents/spans/ai_client.py +42 -0
  102. sentry_sdk/integrations/openai_agents/spans/execute_tool.py +48 -0
  103. sentry_sdk/integrations/openai_agents/spans/handoff.py +19 -0
  104. sentry_sdk/integrations/openai_agents/spans/invoke_agent.py +86 -0
  105. sentry_sdk/integrations/openai_agents/utils.py +199 -0
  106. sentry_sdk/integrations/openfeature.py +35 -0
  107. sentry_sdk/integrations/opentelemetry/__init__.py +7 -0
  108. sentry_sdk/integrations/opentelemetry/consts.py +5 -0
  109. sentry_sdk/integrations/opentelemetry/integration.py +58 -0
  110. sentry_sdk/integrations/opentelemetry/propagator.py +117 -0
  111. sentry_sdk/integrations/opentelemetry/span_processor.py +391 -0
  112. sentry_sdk/integrations/otlp.py +82 -0
  113. sentry_sdk/integrations/pure_eval.py +141 -0
  114. sentry_sdk/integrations/pydantic_ai/__init__.py +47 -0
  115. sentry_sdk/integrations/pydantic_ai/consts.py +1 -0
  116. sentry_sdk/integrations/pydantic_ai/patches/__init__.py +4 -0
  117. sentry_sdk/integrations/pydantic_ai/patches/agent_run.py +215 -0
  118. sentry_sdk/integrations/pydantic_ai/patches/graph_nodes.py +110 -0
  119. sentry_sdk/integrations/pydantic_ai/patches/model_request.py +40 -0
  120. sentry_sdk/integrations/pydantic_ai/patches/tools.py +98 -0
  121. sentry_sdk/integrations/pydantic_ai/spans/__init__.py +3 -0
  122. sentry_sdk/integrations/pydantic_ai/spans/ai_client.py +246 -0
  123. sentry_sdk/integrations/pydantic_ai/spans/execute_tool.py +49 -0
  124. sentry_sdk/integrations/pydantic_ai/spans/invoke_agent.py +112 -0
  125. sentry_sdk/integrations/pydantic_ai/utils.py +223 -0
  126. sentry_sdk/integrations/pymongo.py +214 -0
  127. sentry_sdk/integrations/pyramid.py +112 -68
  128. sentry_sdk/integrations/quart.py +237 -0
  129. sentry_sdk/integrations/ray.py +165 -0
  130. sentry_sdk/integrations/redis/__init__.py +48 -0
  131. sentry_sdk/integrations/redis/_async_common.py +116 -0
  132. sentry_sdk/integrations/redis/_sync_common.py +119 -0
  133. sentry_sdk/integrations/redis/consts.py +19 -0
  134. sentry_sdk/integrations/redis/modules/__init__.py +0 -0
  135. sentry_sdk/integrations/redis/modules/caches.py +118 -0
  136. sentry_sdk/integrations/redis/modules/queries.py +65 -0
  137. sentry_sdk/integrations/redis/rb.py +32 -0
  138. sentry_sdk/integrations/redis/redis.py +69 -0
  139. sentry_sdk/integrations/redis/redis_cluster.py +107 -0
  140. sentry_sdk/integrations/redis/redis_py_cluster_legacy.py +50 -0
  141. sentry_sdk/integrations/redis/utils.py +148 -0
  142. sentry_sdk/integrations/rq.py +95 -37
  143. sentry_sdk/integrations/rust_tracing.py +284 -0
  144. sentry_sdk/integrations/sanic.py +294 -123
  145. sentry_sdk/integrations/serverless.py +48 -19
  146. sentry_sdk/integrations/socket.py +96 -0
  147. sentry_sdk/integrations/spark/__init__.py +4 -0
  148. sentry_sdk/integrations/spark/spark_driver.py +316 -0
  149. sentry_sdk/integrations/spark/spark_worker.py +116 -0
  150. sentry_sdk/integrations/sqlalchemy.py +142 -0
  151. sentry_sdk/integrations/starlette.py +737 -0
  152. sentry_sdk/integrations/starlite.py +292 -0
  153. sentry_sdk/integrations/statsig.py +37 -0
  154. sentry_sdk/integrations/stdlib.py +235 -29
  155. sentry_sdk/integrations/strawberry.py +394 -0
  156. sentry_sdk/integrations/sys_exit.py +70 -0
  157. sentry_sdk/integrations/threading.py +158 -28
  158. sentry_sdk/integrations/tornado.py +84 -52
  159. sentry_sdk/integrations/trytond.py +50 -0
  160. sentry_sdk/integrations/typer.py +60 -0
  161. sentry_sdk/integrations/unleash.py +33 -0
  162. sentry_sdk/integrations/unraisablehook.py +53 -0
  163. sentry_sdk/integrations/wsgi.py +201 -119
  164. sentry_sdk/logger.py +96 -0
  165. sentry_sdk/metrics.py +81 -0
  166. sentry_sdk/monitor.py +120 -0
  167. sentry_sdk/profiler/__init__.py +49 -0
  168. sentry_sdk/profiler/continuous_profiler.py +730 -0
  169. sentry_sdk/profiler/transaction_profiler.py +839 -0
  170. sentry_sdk/profiler/utils.py +195 -0
  171. sentry_sdk/py.typed +0 -0
  172. sentry_sdk/scope.py +1713 -85
  173. sentry_sdk/scrubber.py +177 -0
  174. sentry_sdk/serializer.py +405 -0
  175. sentry_sdk/session.py +177 -0
  176. sentry_sdk/sessions.py +275 -0
  177. sentry_sdk/spotlight.py +242 -0
  178. sentry_sdk/tracing.py +1486 -0
  179. sentry_sdk/tracing_utils.py +1236 -0
  180. sentry_sdk/transport.py +806 -134
  181. sentry_sdk/types.py +52 -0
  182. sentry_sdk/utils.py +1625 -465
  183. sentry_sdk/worker.py +54 -25
  184. sentry_sdk-2.46.0.dist-info/METADATA +268 -0
  185. sentry_sdk-2.46.0.dist-info/RECORD +189 -0
  186. {sentry_sdk-0.7.5.dist-info → sentry_sdk-2.46.0.dist-info}/WHEEL +1 -1
  187. sentry_sdk-2.46.0.dist-info/entry_points.txt +2 -0
  188. sentry_sdk-2.46.0.dist-info/licenses/LICENSE +21 -0
  189. sentry_sdk/integrations/celery.py +0 -119
  190. sentry_sdk-0.7.5.dist-info/LICENSE +0 -9
  191. sentry_sdk-0.7.5.dist-info/METADATA +0 -36
  192. sentry_sdk-0.7.5.dist-info/RECORD +0 -39
  193. {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
- from sentry_sdk.hub import Hub, _should_send_default_pii
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
- from tornado.web import RequestHandler, HTTPError # type: ignore
20
- from tornado.gen import coroutine # type: ignore
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
- if False:
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
- import tornado # type: ignore
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 sys.version_info < (3, 7):
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 RuntimeError(
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: (Any, *List, **Any) -> Any
61
- hub = Hub.current
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
- hub = Hub.current
78
- integration = hub.get_integration(TornadoIntegration)
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=hub.client.options,
140
+ client_options=sentry_sdk.get_client().options,
113
141
  mechanism={"type": "tornado", "handled": False},
114
142
  )
115
143
 
116
- hub.capture_event(event, hint=hint)
144
+ sentry_sdk.capture_event(event, hint=hint)
117
145
 
118
146
 
119
147
  def _make_event_processor(weak_handler):
120
- # type: (Callable[[], RequestHandler]) -> Callable
148
+ # type: (Callable[[], RequestHandler]) -> EventProcessor
121
149
  def tornado_processor(event, hint):
122
- # type: (Dict[str, Any], Dict[str, Any]) -> Dict[str, Any]
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 _should_send_default_pii():
152
- event.setdefault("user", {})["is_authenticated"] = True
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: () -> Optional[Any]
176
- # TODO: Where to get formdata and nothing else?
177
- return None
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