11import functools
2+ import json
23import warnings
34import sys
45from collections .abc import Set
2021)
2122from sentry_sdk .integrations .asgi import SentryAsgiMiddleware
2223from sentry_sdk .scope import should_send_default_pii
24+ from sentry_sdk .traces import NoOpStreamedSpan , StreamedSpan
2325from sentry_sdk .tracing import (
2426 SOURCE_FOR_STYLE ,
2527 TransactionSource ,
2628)
29+ from sentry_sdk .tracing_utils import has_span_streaming_enabled
2730from sentry_sdk .utils import (
2831 AnnotatedValue ,
2932 capture_internal_exceptions ,
@@ -154,7 +157,8 @@ async def _create_span_call(
154157 send : "Callable[[Dict[str, Any]], Awaitable[None]]" ,
155158 ** kwargs : "Any" ,
156159 ) -> None :
157- integration = sentry_sdk .get_client ().get_integration (StarletteIntegration )
160+ client = sentry_sdk .get_client ()
161+ integration = client .get_integration (StarletteIntegration )
158162 if integration is None :
159163 return await old_call (app , scope , receive , send , ** kwargs )
160164
@@ -171,22 +175,38 @@ async def _create_span_call(
171175 return await old_call (app , scope , receive , send , ** kwargs )
172176
173177 middleware_name = app .__class__ .__name__
178+ is_span_streaming_enabled = has_span_streaming_enabled (client .options )
179+
180+ def _start_middleware_span (op : str , name : str ) -> "Any" :
181+ if is_span_streaming_enabled :
182+ return sentry_sdk .traces .start_span (
183+ name = name ,
184+ attributes = {
185+ "sentry.op" : op ,
186+ "sentry.origin" : StarletteIntegration .origin ,
187+ "middleware.name" : middleware_name ,
188+ },
189+ )
190+ return sentry_sdk .start_span (
191+ op = op ,
192+ name = name ,
193+ origin = StarletteIntegration .origin ,
194+ )
174195
175- with sentry_sdk .start_span (
176- op = OP .MIDDLEWARE_STARLETTE ,
177- name = middleware_name ,
178- origin = StarletteIntegration .origin ,
196+ with _start_middleware_span (
197+ op = OP .MIDDLEWARE_STARLETTE , name = middleware_name
179198 ) as middleware_span :
180- middleware_span .set_tag ("starlette.middleware_name" , middleware_name )
199+ if not is_span_streaming_enabled :
200+ middleware_span .set_tag ("starlette.middleware_name" , middleware_name )
181201
182202 # Creating spans for the "receive" callback
183203 async def _sentry_receive (* args : "Any" , ** kwargs : "Any" ) -> "Any" :
184- with sentry_sdk . start_span (
204+ with _start_middleware_span (
185205 op = OP .MIDDLEWARE_STARLETTE_RECEIVE ,
186206 name = getattr (receive , "__qualname__" , str (receive )),
187- origin = StarletteIntegration .origin ,
188207 ) as span :
189- span .set_tag ("starlette.middleware_name" , middleware_name )
208+ if not is_span_streaming_enabled :
209+ span .set_tag ("starlette.middleware_name" , middleware_name )
190210 return await receive (* args , ** kwargs )
191211
192212 receive_name = getattr (receive , "__name__" , str (receive ))
@@ -195,12 +215,12 @@ async def _sentry_receive(*args: "Any", **kwargs: "Any") -> "Any":
195215
196216 # Creating spans for the "send" callback
197217 async def _sentry_send (* args : "Any" , ** kwargs : "Any" ) -> "Any" :
198- with sentry_sdk . start_span (
218+ with _start_middleware_span (
199219 op = OP .MIDDLEWARE_STARLETTE_SEND ,
200220 name = getattr (send , "__qualname__" , str (send )),
201- origin = StarletteIntegration .origin ,
202221 ) as span :
203- span .set_tag ("starlette.middleware_name" , middleware_name )
222+ if not is_span_streaming_enabled :
223+ span .set_tag ("starlette.middleware_name" , middleware_name )
204224 return await send (* args , ** kwargs )
205225
206226 send_name = getattr (send , "__name__" , str (send ))
@@ -221,6 +241,16 @@ async def _sentry_send(*args: "Any", **kwargs: "Any") -> "Any":
221241 return middleware_class
222242
223243
244+ def _serialize_body_data (data : "Any" ) -> str :
245+ # data may be a JSON-serializable value, an AnnotatedValue, or a dict with AnnotatedValue values
246+ def _default (value : "Any" ) -> "Any" :
247+ if isinstance (value , AnnotatedValue ):
248+ return value .value
249+ return str (value )
250+
251+ return json .dumps (data , default = _default )
252+
253+
224254@ensure_integration_enabled (StarletteIntegration )
225255def _capture_exception (exception : BaseException , handled : "Any" = False ) -> None :
226256 event , hint = event_from_exception (
@@ -446,9 +476,8 @@ def _sentry_request_response(func: "Callable[[Any], Any]") -> "ASGIApp":
446476 if is_coroutine :
447477
448478 async def _sentry_async_func (* args : "Any" , ** kwargs : "Any" ) -> "Any" :
449- integration = sentry_sdk .get_client ().get_integration (
450- StarletteIntegration
451- )
479+ client = sentry_sdk .get_client ()
480+ integration = client .get_integration (StarletteIntegration )
452481 if integration is None :
453482 return await old_func (* args , ** kwargs )
454483
@@ -488,6 +517,24 @@ def event_processor(
488517 _make_request_event_processor (request , integration )
489518 )
490519
520+ is_span_streaming_enabled = has_span_streaming_enabled (client .options )
521+ if is_span_streaming_enabled :
522+ current_span = sentry_sdk .get_current_span ()
523+
524+ if (
525+ info
526+ and "data" in info
527+ and isinstance (current_span , StreamedSpan )
528+ and not isinstance (current_span , NoOpStreamedSpan )
529+ ):
530+ data = info ["data" ]
531+
532+ with capture_internal_exceptions ():
533+ current_span ._segment .set_attribute (
534+ "http.request.body.data" ,
535+ _serialize_body_data (data ),
536+ )
537+
491538 return await old_func (* args , ** kwargs )
492539
493540 func = _sentry_async_func
@@ -503,7 +550,13 @@ def _sentry_sync_func(*args: "Any", **kwargs: "Any") -> "Any":
503550 return old_func (* args , ** kwargs )
504551
505552 current_scope = sentry_sdk .get_current_scope ()
506- if current_scope .transaction is not None :
553+ current_span = current_scope .span
554+
555+ if isinstance (current_span , StreamedSpan ) and not isinstance (
556+ current_span , NoOpStreamedSpan
557+ ):
558+ current_span ._segment ._update_active_thread ()
559+ elif current_scope .transaction is not None :
507560 current_scope .transaction .update_active_thread ()
508561
509562 sentry_scope = sentry_sdk .get_isolation_scope ()
0 commit comments