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,37 +1,105 @@
1
1
  import sys
2
2
  import weakref
3
+ from functools import wraps
3
4
 
4
- from sentry_sdk._compat import reraise
5
- from sentry_sdk.hub import Hub
6
- from sentry_sdk.integrations import Integration
5
+ import sentry_sdk
6
+ from sentry_sdk.api import continue_trace
7
+ from sentry_sdk.consts import OP, SPANSTATUS, SPANDATA
8
+ from sentry_sdk.integrations import (
9
+ _DEFAULT_FAILED_REQUEST_STATUS_CODES,
10
+ _check_minimum_version,
11
+ Integration,
12
+ DidNotEnable,
13
+ )
7
14
  from sentry_sdk.integrations.logging import ignore_logger
8
- from sentry_sdk.integrations._wsgi_common import _filter_headers
9
- from sentry_sdk.utils import capture_internal_exceptions, event_from_exception
15
+ from sentry_sdk.sessions import track_session
16
+ from sentry_sdk.integrations._wsgi_common import (
17
+ _filter_headers,
18
+ request_body_within_bounds,
19
+ )
20
+ from sentry_sdk.tracing import (
21
+ BAGGAGE_HEADER_NAME,
22
+ SOURCE_FOR_STYLE,
23
+ TransactionSource,
24
+ )
25
+ from sentry_sdk.tracing_utils import should_propagate_trace, add_http_request_source
26
+ from sentry_sdk.utils import (
27
+ capture_internal_exceptions,
28
+ ensure_integration_enabled,
29
+ event_from_exception,
30
+ logger,
31
+ parse_url,
32
+ parse_version,
33
+ reraise,
34
+ transaction_from_function,
35
+ HAS_REAL_CONTEXTVARS,
36
+ CONTEXTVARS_ERROR_MESSAGE,
37
+ SENSITIVE_DATA_SUBSTITUTE,
38
+ AnnotatedValue,
39
+ )
10
40
 
11
- import asyncio
12
- from aiohttp.web import Application, HTTPException # type: ignore
41
+ try:
42
+ import asyncio
13
43
 
14
- if False:
15
- from aiohttp.web_request import Request # type: ignore
44
+ from aiohttp import __version__ as AIOHTTP_VERSION
45
+ from aiohttp import ClientSession, TraceConfig
46
+ from aiohttp.web import Application, HTTPException, UrlDispatcher
47
+ except ImportError:
48
+ raise DidNotEnable("AIOHTTP not installed")
49
+
50
+ from typing import TYPE_CHECKING
51
+
52
+ if TYPE_CHECKING:
53
+ from aiohttp.web_request import Request
54
+ from aiohttp.web_urldispatcher import UrlMappingMatchInfo
55
+ from aiohttp import TraceRequestStartParams, TraceRequestEndParams
56
+
57
+ from collections.abc import Set
58
+ from types import SimpleNamespace
16
59
  from typing import Any
17
- from typing import Dict
60
+ from typing import Optional
18
61
  from typing import Tuple
19
- from typing import Callable
62
+ from typing import Union
20
63
 
21
64
  from sentry_sdk.utils import ExcInfo
65
+ from sentry_sdk._types import Event, EventProcessor
66
+
67
+
68
+ TRANSACTION_STYLE_VALUES = ("handler_name", "method_and_path_pattern")
22
69
 
23
70
 
24
71
  class AioHttpIntegration(Integration):
25
72
  identifier = "aiohttp"
73
+ origin = f"auto.http.{identifier}"
74
+
75
+ def __init__(
76
+ self,
77
+ transaction_style="handler_name", # type: str
78
+ *,
79
+ failed_request_status_codes=_DEFAULT_FAILED_REQUEST_STATUS_CODES, # type: Set[int]
80
+ ):
81
+ # type: (...) -> None
82
+ if transaction_style not in TRANSACTION_STYLE_VALUES:
83
+ raise ValueError(
84
+ "Invalid value for transaction_style: %s (must be in %s)"
85
+ % (transaction_style, TRANSACTION_STYLE_VALUES)
86
+ )
87
+ self.transaction_style = transaction_style
88
+ self._failed_request_status_codes = failed_request_status_codes
26
89
 
27
90
  @staticmethod
28
91
  def setup_once():
29
92
  # type: () -> None
30
- if sys.version_info < (3, 7):
93
+
94
+ version = parse_version(AIOHTTP_VERSION)
95
+ _check_minimum_version(AioHttpIntegration, version)
96
+
97
+ if not HAS_REAL_CONTEXTVARS:
31
98
  # We better have contextvars or we're going to leak state between
32
99
  # requests.
33
- raise RuntimeError(
34
- "The aiohttp integration for Sentry requires Python 3.7+"
100
+ raise DidNotEnable(
101
+ "The aiohttp integration for Sentry requires Python 3.7+ "
102
+ " or aiocontextvars package." + CONTEXTVARS_ERROR_MESSAGE
35
103
  )
36
104
 
37
105
  ignore_logger("aiohttp.server")
@@ -40,47 +108,200 @@ class AioHttpIntegration(Integration):
40
108
 
41
109
  async def sentry_app_handle(self, request, *args, **kwargs):
42
110
  # type: (Any, Request, *Any, **Any) -> Any
43
- async def inner():
44
- # type: () -> Any
45
- hub = Hub.current
46
- if hub.get_integration(AioHttpIntegration) is None:
47
- return await old_handle(self, request, *args, **kwargs)
111
+ integration = sentry_sdk.get_client().get_integration(AioHttpIntegration)
112
+ if integration is None:
113
+ return await old_handle(self, request, *args, **kwargs)
48
114
 
49
- weak_request = weakref.ref(request)
115
+ weak_request = weakref.ref(request)
50
116
 
51
- with Hub(Hub.current) as hub:
52
- with hub.configure_scope() as scope:
53
- scope.add_event_processor(_make_request_processor(weak_request))
117
+ with sentry_sdk.isolation_scope() as scope:
118
+ with track_session(scope, session_mode="request"):
119
+ # Scope data will not leak between requests because aiohttp
120
+ # create a task to wrap each request.
121
+ scope.generate_propagation_context()
122
+ scope.clear_breadcrumbs()
123
+ scope.add_event_processor(_make_request_processor(weak_request))
54
124
 
55
- try:
56
- response = await old_handle(self, request)
57
- except HTTPException:
58
- raise
59
- except Exception:
60
- reraise(*_capture_exception(hub))
125
+ headers = dict(request.headers)
126
+ transaction = continue_trace(
127
+ headers,
128
+ op=OP.HTTP_SERVER,
129
+ # If this transaction name makes it to the UI, AIOHTTP's
130
+ # URL resolver did not find a route or died trying.
131
+ name="generic AIOHTTP request",
132
+ source=TransactionSource.ROUTE,
133
+ origin=AioHttpIntegration.origin,
134
+ )
135
+ with sentry_sdk.start_transaction(
136
+ transaction,
137
+ custom_sampling_context={"aiohttp_request": request},
138
+ ):
139
+ try:
140
+ response = await old_handle(self, request)
141
+ except HTTPException as e:
142
+ transaction.set_http_status(e.status_code)
61
143
 
62
- return response
144
+ if (
145
+ e.status_code
146
+ in integration._failed_request_status_codes
147
+ ):
148
+ _capture_exception()
63
149
 
64
- return await asyncio.create_task(inner())
150
+ raise
151
+ except (asyncio.CancelledError, ConnectionResetError):
152
+ transaction.set_status(SPANSTATUS.CANCELLED)
153
+ raise
154
+ except Exception:
155
+ # This will probably map to a 500 but seems like we
156
+ # have no way to tell. Do not set span status.
157
+ reraise(*_capture_exception())
158
+
159
+ try:
160
+ # A valid response handler will return a valid response with a status. But, if the handler
161
+ # returns an invalid response (e.g. None), the line below will raise an AttributeError.
162
+ # Even though this is likely invalid, we need to handle this case to ensure we don't break
163
+ # the application.
164
+ response_status = response.status
165
+ except AttributeError:
166
+ pass
167
+ else:
168
+ transaction.set_http_status(response_status)
169
+
170
+ return response
65
171
 
66
172
  Application._handle = sentry_app_handle
67
173
 
174
+ old_urldispatcher_resolve = UrlDispatcher.resolve
175
+
176
+ @wraps(old_urldispatcher_resolve)
177
+ async def sentry_urldispatcher_resolve(self, request):
178
+ # type: (UrlDispatcher, Request) -> UrlMappingMatchInfo
179
+ rv = await old_urldispatcher_resolve(self, request)
180
+
181
+ integration = sentry_sdk.get_client().get_integration(AioHttpIntegration)
182
+ if integration is None:
183
+ return rv
184
+
185
+ name = None
186
+
187
+ try:
188
+ if integration.transaction_style == "handler_name":
189
+ name = transaction_from_function(rv.handler)
190
+ elif integration.transaction_style == "method_and_path_pattern":
191
+ route_info = rv.get_info()
192
+ pattern = route_info.get("path") or route_info.get("formatter")
193
+ name = "{} {}".format(request.method, pattern)
194
+ except Exception:
195
+ pass
196
+
197
+ if name is not None:
198
+ sentry_sdk.get_current_scope().set_transaction_name(
199
+ name,
200
+ source=SOURCE_FOR_STYLE[integration.transaction_style],
201
+ )
202
+
203
+ return rv
204
+
205
+ UrlDispatcher.resolve = sentry_urldispatcher_resolve
206
+
207
+ old_client_session_init = ClientSession.__init__
208
+
209
+ @ensure_integration_enabled(AioHttpIntegration, old_client_session_init)
210
+ def init(*args, **kwargs):
211
+ # type: (Any, Any) -> None
212
+ client_trace_configs = list(kwargs.get("trace_configs") or ())
213
+ trace_config = create_trace_config()
214
+ client_trace_configs.append(trace_config)
215
+
216
+ kwargs["trace_configs"] = client_trace_configs
217
+ return old_client_session_init(*args, **kwargs)
218
+
219
+ ClientSession.__init__ = init
220
+
221
+
222
+ def create_trace_config():
223
+ # type: () -> TraceConfig
224
+
225
+ async def on_request_start(session, trace_config_ctx, params):
226
+ # type: (ClientSession, SimpleNamespace, TraceRequestStartParams) -> None
227
+ if sentry_sdk.get_client().get_integration(AioHttpIntegration) is None:
228
+ return
229
+
230
+ method = params.method.upper()
231
+
232
+ parsed_url = None
233
+ with capture_internal_exceptions():
234
+ parsed_url = parse_url(str(params.url), sanitize=False)
235
+
236
+ span = sentry_sdk.start_span(
237
+ op=OP.HTTP_CLIENT,
238
+ name="%s %s"
239
+ % (method, parsed_url.url if parsed_url else SENSITIVE_DATA_SUBSTITUTE),
240
+ origin=AioHttpIntegration.origin,
241
+ )
242
+ span.set_data(SPANDATA.HTTP_METHOD, method)
243
+ if parsed_url is not None:
244
+ span.set_data("url", parsed_url.url)
245
+ span.set_data(SPANDATA.HTTP_QUERY, parsed_url.query)
246
+ span.set_data(SPANDATA.HTTP_FRAGMENT, parsed_url.fragment)
247
+
248
+ client = sentry_sdk.get_client()
249
+
250
+ if should_propagate_trace(client, str(params.url)):
251
+ for (
252
+ key,
253
+ value,
254
+ ) in sentry_sdk.get_current_scope().iter_trace_propagation_headers(
255
+ span=span
256
+ ):
257
+ logger.debug(
258
+ "[Tracing] Adding `{key}` header {value} to outgoing request to {url}.".format(
259
+ key=key, value=value, url=params.url
260
+ )
261
+ )
262
+ if key == BAGGAGE_HEADER_NAME and params.headers.get(
263
+ BAGGAGE_HEADER_NAME
264
+ ):
265
+ # do not overwrite any existing baggage, just append to it
266
+ params.headers[key] += "," + value
267
+ else:
268
+ params.headers[key] = value
269
+
270
+ trace_config_ctx.span = span
271
+
272
+ async def on_request_end(session, trace_config_ctx, params):
273
+ # type: (ClientSession, SimpleNamespace, TraceRequestEndParams) -> None
274
+ if trace_config_ctx.span is None:
275
+ return
276
+
277
+ span = trace_config_ctx.span
278
+ span.set_http_status(int(params.response.status))
279
+ span.set_data("reason", params.response.reason)
280
+ span.finish()
281
+
282
+ with capture_internal_exceptions():
283
+ add_http_request_source(span)
284
+
285
+ trace_config = TraceConfig()
286
+
287
+ trace_config.on_request_start.append(on_request_start)
288
+ trace_config.on_request_end.append(on_request_end)
289
+
290
+ return trace_config
291
+
68
292
 
69
293
  def _make_request_processor(weak_request):
70
- # type: (Callable[[], Request]) -> Callable
294
+ # type: (weakref.ReferenceType[Request]) -> EventProcessor
71
295
  def aiohttp_processor(
72
- event, # type: Dict[str, Any]
73
- hint, # type: Dict[str, Tuple[type, BaseException, Any]]
296
+ event, # type: Event
297
+ hint, # type: dict[str, Tuple[type, BaseException, Any]]
74
298
  ):
75
- # type: (...) -> Dict[str, Any]
299
+ # type: (...) -> Event
76
300
  request = weak_request()
77
301
  if request is None:
78
302
  return event
79
303
 
80
304
  with capture_internal_exceptions():
81
- # TODO: Figure out what to do with request body. Methods on request
82
- # are async, but event processors are not.
83
-
84
305
  request_info = event.setdefault("request", {})
85
306
 
86
307
  request_info["url"] = "%s://%s%s" % (
@@ -94,18 +315,46 @@ def _make_request_processor(weak_request):
94
315
  request_info["env"] = {"REMOTE_ADDR": request.remote}
95
316
  request_info["headers"] = _filter_headers(dict(request.headers))
96
317
 
318
+ # Just attach raw data here if it is within bounds, if available.
319
+ # Unfortunately there's no way to get structured data from aiohttp
320
+ # without awaiting on some coroutine.
321
+ request_info["data"] = get_aiohttp_request_data(request)
322
+
97
323
  return event
98
324
 
99
325
  return aiohttp_processor
100
326
 
101
327
 
102
- def _capture_exception(hub):
103
- # type: (Hub) -> ExcInfo
328
+ def _capture_exception():
329
+ # type: () -> ExcInfo
104
330
  exc_info = sys.exc_info()
105
331
  event, hint = event_from_exception(
106
332
  exc_info,
107
- client_options=hub.client.options, # type: ignore
333
+ client_options=sentry_sdk.get_client().options,
108
334
  mechanism={"type": "aiohttp", "handled": False},
109
335
  )
110
- hub.capture_event(event, hint=hint)
336
+ sentry_sdk.capture_event(event, hint=hint)
111
337
  return exc_info
338
+
339
+
340
+ BODY_NOT_READ_MESSAGE = "[Can't show request body due to implementation details.]"
341
+
342
+
343
+ def get_aiohttp_request_data(request):
344
+ # type: (Request) -> Union[Optional[str], AnnotatedValue]
345
+ bytes_body = request._read_bytes
346
+
347
+ if bytes_body is not None:
348
+ # we have body to show
349
+ if not request_body_within_bounds(sentry_sdk.get_client(), len(bytes_body)):
350
+ return AnnotatedValue.removed_because_over_size_limit()
351
+
352
+ encoding = request.charset or "utf-8"
353
+ return bytes_body.decode(encoding, "replace")
354
+
355
+ if request.can_read_body:
356
+ # body exists but we can't show it
357
+ return BODY_NOT_READ_MESSAGE
358
+
359
+ # request has no body
360
+ return None