sentry-sdk 0.18.0__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 -6
  2. sentry_sdk/_compat.py +64 -56
  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 +81 -19
  8. sentry_sdk/_types.py +311 -11
  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 +409 -67
  14. sentry_sdk/attachments.py +75 -0
  15. sentry_sdk/client.py +849 -103
  16. sentry_sdk/consts.py +1389 -34
  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 +12 -15
  22. sentry_sdk/envelope.py +112 -61
  23. sentry_sdk/feature_flags.py +71 -0
  24. sentry_sdk/hub.py +442 -386
  25. sentry_sdk/integrations/__init__.py +228 -58
  26. sentry_sdk/integrations/_asgi_common.py +108 -0
  27. sentry_sdk/integrations/_wsgi_common.py +131 -40
  28. sentry_sdk/integrations/aiohttp.py +221 -72
  29. sentry_sdk/integrations/anthropic.py +439 -0
  30. sentry_sdk/integrations/argv.py +4 -6
  31. sentry_sdk/integrations/ariadne.py +161 -0
  32. sentry_sdk/integrations/arq.py +247 -0
  33. sentry_sdk/integrations/asgi.py +237 -135
  34. sentry_sdk/integrations/asyncio.py +144 -0
  35. sentry_sdk/integrations/asyncpg.py +208 -0
  36. sentry_sdk/integrations/atexit.py +13 -18
  37. sentry_sdk/integrations/aws_lambda.py +233 -80
  38. sentry_sdk/integrations/beam.py +27 -35
  39. sentry_sdk/integrations/boto3.py +137 -0
  40. sentry_sdk/integrations/bottle.py +91 -69
  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 +35 -28
  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 +32 -8
  49. sentry_sdk/integrations/django/__init__.py +343 -89
  50. sentry_sdk/integrations/django/asgi.py +201 -22
  51. sentry_sdk/integrations/django/caching.py +204 -0
  52. sentry_sdk/integrations/django/middleware.py +80 -32
  53. sentry_sdk/integrations/django/signals_handlers.py +91 -0
  54. sentry_sdk/integrations/django/templates.py +69 -2
  55. sentry_sdk/integrations/django/transactions.py +39 -14
  56. sentry_sdk/integrations/django/views.py +69 -16
  57. sentry_sdk/integrations/dramatiq.py +226 -0
  58. sentry_sdk/integrations/excepthook.py +19 -13
  59. sentry_sdk/integrations/executing.py +5 -6
  60. sentry_sdk/integrations/falcon.py +128 -65
  61. sentry_sdk/integrations/fastapi.py +141 -0
  62. sentry_sdk/integrations/flask.py +114 -75
  63. sentry_sdk/integrations/gcp.py +67 -36
  64. sentry_sdk/integrations/gnu_backtrace.py +14 -22
  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 +261 -85
  87. sentry_sdk/integrations/loguru.py +213 -0
  88. sentry_sdk/integrations/mcp.py +566 -0
  89. sentry_sdk/integrations/modules.py +6 -33
  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 +20 -11
  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 +71 -60
  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 +62 -52
  143. sentry_sdk/integrations/rust_tracing.py +284 -0
  144. sentry_sdk/integrations/sanic.py +248 -114
  145. sentry_sdk/integrations/serverless.py +13 -22
  146. sentry_sdk/integrations/socket.py +96 -0
  147. sentry_sdk/integrations/spark/spark_driver.py +115 -62
  148. sentry_sdk/integrations/spark/spark_worker.py +42 -50
  149. sentry_sdk/integrations/sqlalchemy.py +82 -37
  150. sentry_sdk/integrations/starlette.py +737 -0
  151. sentry_sdk/integrations/starlite.py +292 -0
  152. sentry_sdk/integrations/statsig.py +37 -0
  153. sentry_sdk/integrations/stdlib.py +100 -58
  154. sentry_sdk/integrations/strawberry.py +394 -0
  155. sentry_sdk/integrations/sys_exit.py +70 -0
  156. sentry_sdk/integrations/threading.py +142 -38
  157. sentry_sdk/integrations/tornado.py +68 -53
  158. sentry_sdk/integrations/trytond.py +15 -20
  159. sentry_sdk/integrations/typer.py +60 -0
  160. sentry_sdk/integrations/unleash.py +33 -0
  161. sentry_sdk/integrations/unraisablehook.py +53 -0
  162. sentry_sdk/integrations/wsgi.py +126 -125
  163. sentry_sdk/logger.py +96 -0
  164. sentry_sdk/metrics.py +81 -0
  165. sentry_sdk/monitor.py +120 -0
  166. sentry_sdk/profiler/__init__.py +49 -0
  167. sentry_sdk/profiler/continuous_profiler.py +730 -0
  168. sentry_sdk/profiler/transaction_profiler.py +839 -0
  169. sentry_sdk/profiler/utils.py +195 -0
  170. sentry_sdk/scope.py +1542 -112
  171. sentry_sdk/scrubber.py +177 -0
  172. sentry_sdk/serializer.py +152 -210
  173. sentry_sdk/session.py +177 -0
  174. sentry_sdk/sessions.py +202 -179
  175. sentry_sdk/spotlight.py +242 -0
  176. sentry_sdk/tracing.py +1202 -294
  177. sentry_sdk/tracing_utils.py +1236 -0
  178. sentry_sdk/transport.py +693 -189
  179. sentry_sdk/types.py +52 -0
  180. sentry_sdk/utils.py +1395 -228
  181. sentry_sdk/worker.py +30 -17
  182. sentry_sdk-2.46.0.dist-info/METADATA +268 -0
  183. sentry_sdk-2.46.0.dist-info/RECORD +189 -0
  184. {sentry_sdk-0.18.0.dist-info → sentry_sdk-2.46.0.dist-info}/WHEEL +1 -1
  185. sentry_sdk-2.46.0.dist-info/entry_points.txt +2 -0
  186. sentry_sdk-2.46.0.dist-info/licenses/LICENSE +21 -0
  187. sentry_sdk/_functools.py +0 -66
  188. sentry_sdk/integrations/celery.py +0 -275
  189. sentry_sdk/integrations/redis.py +0 -103
  190. sentry_sdk-0.18.0.dist-info/LICENSE +0 -9
  191. sentry_sdk-0.18.0.dist-info/METADATA +0 -66
  192. sentry_sdk-0.18.0.dist-info/RECORD +0 -65
  193. {sentry_sdk-0.18.0.dist-info → sentry_sdk-2.46.0.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,292 @@
1
+ from copy import deepcopy
2
+
3
+ import sentry_sdk
4
+ from sentry_sdk.consts import OP
5
+ from sentry_sdk.integrations import DidNotEnable, Integration
6
+ from sentry_sdk.integrations.asgi import SentryAsgiMiddleware
7
+ from sentry_sdk.scope import should_send_default_pii
8
+ from sentry_sdk.tracing import SOURCE_FOR_STYLE, TransactionSource
9
+ from sentry_sdk.utils import (
10
+ ensure_integration_enabled,
11
+ event_from_exception,
12
+ transaction_from_function,
13
+ )
14
+
15
+ try:
16
+ from starlite import Request, Starlite, State # type: ignore
17
+ from starlite.handlers.base import BaseRouteHandler # type: ignore
18
+ from starlite.middleware import DefineMiddleware # type: ignore
19
+ from starlite.plugins.base import get_plugin_for_value # type: ignore
20
+ from starlite.routes.http import HTTPRoute # type: ignore
21
+ from starlite.utils import ConnectionDataExtractor, is_async_callable, Ref # type: ignore
22
+ from pydantic import BaseModel # type: ignore
23
+ except ImportError:
24
+ raise DidNotEnable("Starlite is not installed")
25
+
26
+ from typing import TYPE_CHECKING
27
+
28
+ if TYPE_CHECKING:
29
+ from typing import Any, Optional, Union
30
+ from starlite.types import ( # type: ignore
31
+ ASGIApp,
32
+ Hint,
33
+ HTTPReceiveMessage,
34
+ HTTPScope,
35
+ Message,
36
+ Middleware,
37
+ Receive,
38
+ Scope as StarliteScope,
39
+ Send,
40
+ WebSocketReceiveMessage,
41
+ )
42
+ from starlite import MiddlewareProtocol
43
+ from sentry_sdk._types import Event
44
+
45
+
46
+ _DEFAULT_TRANSACTION_NAME = "generic Starlite request"
47
+
48
+
49
+ class StarliteIntegration(Integration):
50
+ identifier = "starlite"
51
+ origin = f"auto.http.{identifier}"
52
+
53
+ @staticmethod
54
+ def setup_once():
55
+ # type: () -> None
56
+ patch_app_init()
57
+ patch_middlewares()
58
+ patch_http_route_handle()
59
+
60
+
61
+ class SentryStarliteASGIMiddleware(SentryAsgiMiddleware):
62
+ def __init__(self, app, span_origin=StarliteIntegration.origin):
63
+ # type: (ASGIApp, str) -> None
64
+ super().__init__(
65
+ app=app,
66
+ unsafe_context_data=False,
67
+ transaction_style="endpoint",
68
+ mechanism_type="asgi",
69
+ span_origin=span_origin,
70
+ asgi_version=3,
71
+ )
72
+
73
+
74
+ def patch_app_init():
75
+ # type: () -> None
76
+ """
77
+ Replaces the Starlite class's `__init__` function in order to inject `after_exception` handlers and set the
78
+ `SentryStarliteASGIMiddleware` as the outmost middleware in the stack.
79
+ See:
80
+ - https://starlite-api.github.io/starlite/usage/0-the-starlite-app/5-application-hooks/#after-exception
81
+ - https://starlite-api.github.io/starlite/usage/7-middleware/0-middleware-intro/
82
+ """
83
+ old__init__ = Starlite.__init__
84
+
85
+ @ensure_integration_enabled(StarliteIntegration, old__init__)
86
+ def injection_wrapper(self, *args, **kwargs):
87
+ # type: (Starlite, *Any, **Any) -> None
88
+ after_exception = kwargs.pop("after_exception", [])
89
+ kwargs.update(
90
+ after_exception=[
91
+ exception_handler,
92
+ *(
93
+ after_exception
94
+ if isinstance(after_exception, list)
95
+ else [after_exception]
96
+ ),
97
+ ]
98
+ )
99
+
100
+ middleware = kwargs.get("middleware") or []
101
+ kwargs["middleware"] = [SentryStarliteASGIMiddleware, *middleware]
102
+ old__init__(self, *args, **kwargs)
103
+
104
+ Starlite.__init__ = injection_wrapper
105
+
106
+
107
+ def patch_middlewares():
108
+ # type: () -> None
109
+ old_resolve_middleware_stack = BaseRouteHandler.resolve_middleware
110
+
111
+ @ensure_integration_enabled(StarliteIntegration, old_resolve_middleware_stack)
112
+ def resolve_middleware_wrapper(self):
113
+ # type: (BaseRouteHandler) -> list[Middleware]
114
+ return [
115
+ enable_span_for_middleware(middleware)
116
+ for middleware in old_resolve_middleware_stack(self)
117
+ ]
118
+
119
+ BaseRouteHandler.resolve_middleware = resolve_middleware_wrapper
120
+
121
+
122
+ def enable_span_for_middleware(middleware):
123
+ # type: (Middleware) -> Middleware
124
+ if (
125
+ not hasattr(middleware, "__call__") # noqa: B004
126
+ or middleware is SentryStarliteASGIMiddleware
127
+ ):
128
+ return middleware
129
+
130
+ if isinstance(middleware, DefineMiddleware):
131
+ old_call = middleware.middleware.__call__ # type: ASGIApp
132
+ else:
133
+ old_call = middleware.__call__
134
+
135
+ async def _create_span_call(self, scope, receive, send):
136
+ # type: (MiddlewareProtocol, StarliteScope, Receive, Send) -> None
137
+ if sentry_sdk.get_client().get_integration(StarliteIntegration) is None:
138
+ return await old_call(self, scope, receive, send)
139
+
140
+ middleware_name = self.__class__.__name__
141
+ with sentry_sdk.start_span(
142
+ op=OP.MIDDLEWARE_STARLITE,
143
+ name=middleware_name,
144
+ origin=StarliteIntegration.origin,
145
+ ) as middleware_span:
146
+ middleware_span.set_tag("starlite.middleware_name", middleware_name)
147
+
148
+ # Creating spans for the "receive" callback
149
+ async def _sentry_receive(*args, **kwargs):
150
+ # type: (*Any, **Any) -> Union[HTTPReceiveMessage, WebSocketReceiveMessage]
151
+ if sentry_sdk.get_client().get_integration(StarliteIntegration) is None:
152
+ return await receive(*args, **kwargs)
153
+ with sentry_sdk.start_span(
154
+ op=OP.MIDDLEWARE_STARLITE_RECEIVE,
155
+ name=getattr(receive, "__qualname__", str(receive)),
156
+ origin=StarliteIntegration.origin,
157
+ ) as span:
158
+ span.set_tag("starlite.middleware_name", middleware_name)
159
+ return await receive(*args, **kwargs)
160
+
161
+ receive_name = getattr(receive, "__name__", str(receive))
162
+ receive_patched = receive_name == "_sentry_receive"
163
+ new_receive = _sentry_receive if not receive_patched else receive
164
+
165
+ # Creating spans for the "send" callback
166
+ async def _sentry_send(message):
167
+ # type: (Message) -> None
168
+ if sentry_sdk.get_client().get_integration(StarliteIntegration) is None:
169
+ return await send(message)
170
+ with sentry_sdk.start_span(
171
+ op=OP.MIDDLEWARE_STARLITE_SEND,
172
+ name=getattr(send, "__qualname__", str(send)),
173
+ origin=StarliteIntegration.origin,
174
+ ) as span:
175
+ span.set_tag("starlite.middleware_name", middleware_name)
176
+ return await send(message)
177
+
178
+ send_name = getattr(send, "__name__", str(send))
179
+ send_patched = send_name == "_sentry_send"
180
+ new_send = _sentry_send if not send_patched else send
181
+
182
+ return await old_call(self, scope, new_receive, new_send)
183
+
184
+ not_yet_patched = old_call.__name__ not in ["_create_span_call"]
185
+
186
+ if not_yet_patched:
187
+ if isinstance(middleware, DefineMiddleware):
188
+ middleware.middleware.__call__ = _create_span_call
189
+ else:
190
+ middleware.__call__ = _create_span_call
191
+
192
+ return middleware
193
+
194
+
195
+ def patch_http_route_handle():
196
+ # type: () -> None
197
+ old_handle = HTTPRoute.handle
198
+
199
+ async def handle_wrapper(self, scope, receive, send):
200
+ # type: (HTTPRoute, HTTPScope, Receive, Send) -> None
201
+ if sentry_sdk.get_client().get_integration(StarliteIntegration) is None:
202
+ return await old_handle(self, scope, receive, send)
203
+
204
+ sentry_scope = sentry_sdk.get_isolation_scope()
205
+ request = scope["app"].request_class(scope=scope, receive=receive, send=send) # type: Request[Any, Any]
206
+ extracted_request_data = ConnectionDataExtractor(
207
+ parse_body=True, parse_query=True
208
+ )(request)
209
+ body = extracted_request_data.pop("body")
210
+
211
+ request_data = await body
212
+
213
+ def event_processor(event, _):
214
+ # type: (Event, Hint) -> Event
215
+ route_handler = scope.get("route_handler")
216
+
217
+ request_info = event.get("request", {})
218
+ request_info["content_length"] = len(scope.get("_body", b""))
219
+ if should_send_default_pii():
220
+ request_info["cookies"] = extracted_request_data["cookies"]
221
+ if request_data is not None:
222
+ request_info["data"] = request_data
223
+
224
+ func = None
225
+ if route_handler.name is not None:
226
+ tx_name = route_handler.name
227
+ elif isinstance(route_handler.fn, Ref):
228
+ func = route_handler.fn.value
229
+ else:
230
+ func = route_handler.fn
231
+ if func is not None:
232
+ tx_name = transaction_from_function(func)
233
+
234
+ tx_info = {"source": SOURCE_FOR_STYLE["endpoint"]}
235
+
236
+ if not tx_name:
237
+ tx_name = _DEFAULT_TRANSACTION_NAME
238
+ tx_info = {"source": TransactionSource.ROUTE}
239
+
240
+ event.update(
241
+ {
242
+ "request": deepcopy(request_info),
243
+ "transaction": tx_name,
244
+ "transaction_info": tx_info,
245
+ }
246
+ )
247
+ return event
248
+
249
+ sentry_scope._name = StarliteIntegration.identifier
250
+ sentry_scope.add_event_processor(event_processor)
251
+
252
+ return await old_handle(self, scope, receive, send)
253
+
254
+ HTTPRoute.handle = handle_wrapper
255
+
256
+
257
+ def retrieve_user_from_scope(scope):
258
+ # type: (StarliteScope) -> Optional[dict[str, Any]]
259
+ scope_user = scope.get("user")
260
+ if not scope_user:
261
+ return None
262
+ if isinstance(scope_user, dict):
263
+ return scope_user
264
+ if isinstance(scope_user, BaseModel):
265
+ return scope_user.dict()
266
+ if hasattr(scope_user, "asdict"): # dataclasses
267
+ return scope_user.asdict()
268
+
269
+ plugin = get_plugin_for_value(scope_user)
270
+ if plugin and not is_async_callable(plugin.to_dict):
271
+ return plugin.to_dict(scope_user)
272
+
273
+ return None
274
+
275
+
276
+ @ensure_integration_enabled(StarliteIntegration)
277
+ def exception_handler(exc, scope, _):
278
+ # type: (Exception, StarliteScope, State) -> None
279
+ user_info = None # type: Optional[dict[str, Any]]
280
+ if should_send_default_pii():
281
+ user_info = retrieve_user_from_scope(scope)
282
+ if user_info and isinstance(user_info, dict):
283
+ sentry_scope = sentry_sdk.get_isolation_scope()
284
+ sentry_scope.set_user(user_info)
285
+
286
+ event, hint = event_from_exception(
287
+ exc,
288
+ client_options=sentry_sdk.get_client().options,
289
+ mechanism={"type": StarliteIntegration.identifier, "handled": False},
290
+ )
291
+
292
+ sentry_sdk.capture_event(event, hint=hint)
@@ -0,0 +1,37 @@
1
+ from functools import wraps
2
+ from typing import Any, TYPE_CHECKING
3
+
4
+ from sentry_sdk.feature_flags import add_feature_flag
5
+ from sentry_sdk.integrations import Integration, DidNotEnable, _check_minimum_version
6
+ from sentry_sdk.utils import parse_version
7
+
8
+ try:
9
+ from statsig import statsig as statsig_module
10
+ from statsig.version import __version__ as STATSIG_VERSION
11
+ except ImportError:
12
+ raise DidNotEnable("statsig is not installed")
13
+
14
+ if TYPE_CHECKING:
15
+ from statsig.statsig_user import StatsigUser
16
+
17
+
18
+ class StatsigIntegration(Integration):
19
+ identifier = "statsig"
20
+
21
+ @staticmethod
22
+ def setup_once():
23
+ # type: () -> None
24
+ version = parse_version(STATSIG_VERSION)
25
+ _check_minimum_version(StatsigIntegration, version, "statsig")
26
+
27
+ # Wrap and patch evaluation method(s) in the statsig module
28
+ old_check_gate = statsig_module.check_gate
29
+
30
+ @wraps(old_check_gate)
31
+ def sentry_check_gate(user, gate, *args, **kwargs):
32
+ # type: (StatsigUser, str, *Any, **Any) -> Any
33
+ enabled = old_check_gate(user, gate, *args, **kwargs)
34
+ add_feature_flag(gate, enabled)
35
+ return enabled
36
+
37
+ statsig_module.check_gate = sentry_check_gate
@@ -2,16 +2,30 @@ import os
2
2
  import subprocess
3
3
  import sys
4
4
  import platform
5
+ from http.client import HTTPConnection
5
6
 
6
- from sentry_sdk.hub import Hub
7
+ import sentry_sdk
8
+ from sentry_sdk.consts import OP, SPANDATA
7
9
  from sentry_sdk.integrations import Integration
8
10
  from sentry_sdk.scope import add_global_event_processor
9
- from sentry_sdk.tracing import EnvironHeaders
10
- from sentry_sdk.utils import capture_internal_exceptions, safe_repr
11
-
12
- from sentry_sdk._types import MYPY
13
-
14
- if MYPY:
11
+ from sentry_sdk.tracing_utils import (
12
+ EnvironHeaders,
13
+ should_propagate_trace,
14
+ add_http_request_source,
15
+ )
16
+ from sentry_sdk.utils import (
17
+ SENSITIVE_DATA_SUBSTITUTE,
18
+ capture_internal_exceptions,
19
+ ensure_integration_enabled,
20
+ is_sentry_url,
21
+ logger,
22
+ safe_repr,
23
+ parse_url,
24
+ )
25
+
26
+ from typing import TYPE_CHECKING
27
+
28
+ if TYPE_CHECKING:
15
29
  from typing import Any
16
30
  from typing import Callable
17
31
  from typing import Dict
@@ -21,17 +35,11 @@ if MYPY:
21
35
  from sentry_sdk._types import Event, Hint
22
36
 
23
37
 
24
- try:
25
- from httplib import HTTPConnection # type: ignore
26
- except ImportError:
27
- from http.client import HTTPConnection
28
-
29
-
30
38
  _RUNTIME_CONTEXT = {
31
39
  "name": platform.python_implementation(),
32
40
  "version": "%s.%s.%s" % (sys.version_info[:3]),
33
41
  "build": sys.version,
34
- }
42
+ } # type: dict[str, object]
35
43
 
36
44
 
37
45
  class StdlibIntegration(Integration):
@@ -46,7 +54,7 @@ class StdlibIntegration(Integration):
46
54
  @add_global_event_processor
47
55
  def add_python_runtime_context(event, hint):
48
56
  # type: (Event, Hint) -> Optional[Event]
49
- if Hub.current.get_integration(StdlibIntegration) is not None:
57
+ if sentry_sdk.get_client().get_integration(StdlibIntegration) is not None:
50
58
  contexts = event.setdefault("contexts", {})
51
59
  if isinstance(contexts, dict) and "runtime" not in contexts:
52
60
  contexts["runtime"] = _RUNTIME_CONTEXT
@@ -61,16 +69,18 @@ def _install_httplib():
61
69
 
62
70
  def putrequest(self, method, url, *args, **kwargs):
63
71
  # type: (HTTPConnection, str, str, *Any, **Any) -> Any
64
- hub = Hub.current
65
- if hub.get_integration(StdlibIntegration) is None:
66
- return real_putrequest(self, method, url, *args, **kwargs)
67
-
68
72
  host = self.host
69
73
  port = self.port
70
74
  default_port = self.default_port
71
75
 
76
+ client = sentry_sdk.get_client()
77
+ if client.get_integration(StdlibIntegration) is None or is_sentry_url(
78
+ client, host
79
+ ):
80
+ return real_putrequest(self, method, url, *args, **kwargs)
81
+
72
82
  real_url = url
73
- if not real_url.startswith(("http://", "https://")):
83
+ if real_url is None or not real_url.startswith(("http://", "https://")):
74
84
  real_url = "%s://%s%s%s" % (
75
85
  default_port == 443 and "https" or "http",
76
86
  host,
@@ -78,17 +88,39 @@ def _install_httplib():
78
88
  url,
79
89
  )
80
90
 
81
- span = hub.start_span(op="http", description="%s %s" % (method, real_url))
82
-
83
- span.set_data("method", method)
84
- span.set_data("url", real_url)
91
+ parsed_url = None
92
+ with capture_internal_exceptions():
93
+ parsed_url = parse_url(real_url, sanitize=False)
94
+
95
+ span = sentry_sdk.start_span(
96
+ op=OP.HTTP_CLIENT,
97
+ name="%s %s"
98
+ % (method, parsed_url.url if parsed_url else SENSITIVE_DATA_SUBSTITUTE),
99
+ origin="auto.http.stdlib.httplib",
100
+ )
101
+ span.set_data(SPANDATA.HTTP_METHOD, method)
102
+ if parsed_url is not None:
103
+ span.set_data("url", parsed_url.url)
104
+ span.set_data(SPANDATA.HTTP_QUERY, parsed_url.query)
105
+ span.set_data(SPANDATA.HTTP_FRAGMENT, parsed_url.fragment)
85
106
 
86
107
  rv = real_putrequest(self, method, url, *args, **kwargs)
87
108
 
88
- for key, value in hub.iter_trace_propagation_headers():
89
- self.putheader(key, value)
90
-
91
- self._sentrysdk_span = span
109
+ if should_propagate_trace(client, real_url):
110
+ for (
111
+ key,
112
+ value,
113
+ ) in sentry_sdk.get_current_scope().iter_trace_propagation_headers(
114
+ span=span
115
+ ):
116
+ logger.debug(
117
+ "[Tracing] Adding `{key}` header {value} to outgoing request to {real_url}.".format(
118
+ key=key, value=value, real_url=real_url
119
+ )
120
+ )
121
+ self.putheader(key, value)
122
+
123
+ self._sentrysdk_span = span # type: ignore[attr-defined]
92
124
 
93
125
  return rv
94
126
 
@@ -99,17 +131,21 @@ def _install_httplib():
99
131
  if span is None:
100
132
  return real_getresponse(self, *args, **kwargs)
101
133
 
102
- rv = real_getresponse(self, *args, **kwargs)
134
+ try:
135
+ rv = real_getresponse(self, *args, **kwargs)
103
136
 
104
- span.set_data("status_code", rv.status)
105
- span.set_http_status(int(rv.status))
106
- span.set_data("reason", rv.reason)
107
- span.finish()
137
+ span.set_http_status(int(rv.status))
138
+ span.set_data("reason", rv.reason)
139
+ finally:
140
+ span.finish()
141
+
142
+ with capture_internal_exceptions():
143
+ add_http_request_source(span)
108
144
 
109
145
  return rv
110
146
 
111
- HTTPConnection.putrequest = putrequest
112
- HTTPConnection.getresponse = getresponse
147
+ HTTPConnection.putrequest = putrequest # type: ignore[method-assign]
148
+ HTTPConnection.getresponse = getresponse # type: ignore[method-assign]
113
149
 
114
150
 
115
151
  def _init_argument(args, kwargs, name, position, setdefault_callback=None):
@@ -147,13 +183,9 @@ def _install_subprocess():
147
183
  # type: () -> None
148
184
  old_popen_init = subprocess.Popen.__init__
149
185
 
186
+ @ensure_integration_enabled(StdlibIntegration, old_popen_init)
150
187
  def sentry_patched_popen_init(self, *a, **kw):
151
188
  # type: (subprocess.Popen[Any], *Any, **Any) -> None
152
-
153
- hub = Hub.current
154
- if hub.get_integration(StdlibIntegration) is None:
155
- return old_popen_init(self, *a, **kw) # type: ignore
156
-
157
189
  # Convert from tuple to list to be able to set values.
158
190
  a = list(a)
159
191
 
@@ -178,16 +210,28 @@ def _install_subprocess():
178
210
 
179
211
  env = None
180
212
 
181
- for k, v in hub.iter_trace_propagation_headers():
182
- if env is None:
183
- env = _init_argument(a, kw, "env", 10, lambda x: dict(x or os.environ))
184
- env["SUBPROCESS_" + k.upper().replace("-", "_")] = v
213
+ with sentry_sdk.start_span(
214
+ op=OP.SUBPROCESS,
215
+ name=description,
216
+ origin="auto.subprocess.stdlib.subprocess",
217
+ ) as span:
218
+ for k, v in sentry_sdk.get_current_scope().iter_trace_propagation_headers(
219
+ span=span
220
+ ):
221
+ if env is None:
222
+ env = _init_argument(
223
+ a,
224
+ kw,
225
+ "env",
226
+ 10,
227
+ lambda x: dict(x if x is not None else os.environ),
228
+ )
229
+ env["SUBPROCESS_" + k.upper().replace("-", "_")] = v
185
230
 
186
- with hub.start_span(op="subprocess", description=description) as span:
187
231
  if cwd:
188
232
  span.set_data("subprocess.cwd", cwd)
189
233
 
190
- rv = old_popen_init(self, *a, **kw) # type: ignore
234
+ rv = old_popen_init(self, *a, **kw)
191
235
 
192
236
  span.set_tag("subprocess.pid", self.pid)
193
237
  return rv
@@ -196,14 +240,13 @@ def _install_subprocess():
196
240
 
197
241
  old_popen_wait = subprocess.Popen.wait
198
242
 
243
+ @ensure_integration_enabled(StdlibIntegration, old_popen_wait)
199
244
  def sentry_patched_popen_wait(self, *a, **kw):
200
245
  # type: (subprocess.Popen[Any], *Any, **Any) -> Any
201
- hub = Hub.current
202
-
203
- if hub.get_integration(StdlibIntegration) is None:
204
- return old_popen_wait(self, *a, **kw)
205
-
206
- with hub.start_span(op="subprocess.wait") as span:
246
+ with sentry_sdk.start_span(
247
+ op=OP.SUBPROCESS_WAIT,
248
+ origin="auto.subprocess.stdlib.subprocess",
249
+ ) as span:
207
250
  span.set_tag("subprocess.pid", self.pid)
208
251
  return old_popen_wait(self, *a, **kw)
209
252
 
@@ -211,14 +254,13 @@ def _install_subprocess():
211
254
 
212
255
  old_popen_communicate = subprocess.Popen.communicate
213
256
 
257
+ @ensure_integration_enabled(StdlibIntegration, old_popen_communicate)
214
258
  def sentry_patched_popen_communicate(self, *a, **kw):
215
259
  # type: (subprocess.Popen[Any], *Any, **Any) -> Any
216
- hub = Hub.current
217
-
218
- if hub.get_integration(StdlibIntegration) is None:
219
- return old_popen_communicate(self, *a, **kw)
220
-
221
- with hub.start_span(op="subprocess.communicate") as span:
260
+ with sentry_sdk.start_span(
261
+ op=OP.SUBPROCESS_COMMUNICATE,
262
+ origin="auto.subprocess.stdlib.subprocess",
263
+ ) as span:
222
264
  span.set_tag("subprocess.pid", self.pid)
223
265
  return old_popen_communicate(self, *a, **kw)
224
266