55from sentry_sdk import start_span
66from sentry_sdk .consts import OP , SPANDATA
77from sentry_sdk .integrations import DidNotEnable , Integration
8+ from sentry_sdk .traces import StreamedSpan
89from sentry_sdk .tracing import BAGGAGE_HEADER_NAME
910from sentry_sdk .tracing_utils import (
1011 add_http_request_source ,
1112 add_sentry_baggage_to_headers ,
13+ has_span_streaming_enabled ,
1214 should_propagate_trace ,
1315)
1416from sentry_sdk .utils import (
@@ -83,6 +85,44 @@ def _sentry_pyreqwest_span(request: "Request") -> "Generator[Any, None, None]":
8385 with capture_internal_exceptions ():
8486 parsed_url = parse_url (str (request .url ), sanitize = False )
8587
88+ client = sentry_sdk .get_client ()
89+ if has_span_streaming_enabled (client .options ):
90+ with sentry_sdk .traces .start_span (
91+ name = f"{ request .method } { parsed_url .url if parsed_url else SENSITIVE_DATA_SUBSTITUTE } " ,
92+ attributes = {
93+ "sentry.op" : OP .HTTP_CLIENT ,
94+ "sentry.origin" : PyreqwestIntegration .origin ,
95+ SPANDATA .HTTP_METHOD : request .method ,
96+ },
97+ ) as span :
98+ if parsed_url is not None :
99+ span .set_attribute ("url" , parsed_url .url )
100+ span .set_attribute (SPANDATA .HTTP_QUERY , parsed_url .query )
101+ span .set_attribute (SPANDATA .HTTP_FRAGMENT , parsed_url .fragment )
102+
103+ if should_propagate_trace (sentry_sdk .get_client (), str (request .url )):
104+ for (
105+ key ,
106+ value ,
107+ ) in sentry_sdk .get_current_scope ().iter_trace_propagation_headers ():
108+ logger .debug (
109+ "[Tracing] Adding `{key}` header {value} to outgoing request to {url}." .format (
110+ key = key , value = value , url = request .url
111+ )
112+ )
113+
114+ if key == BAGGAGE_HEADER_NAME :
115+ add_sentry_baggage_to_headers (request .headers , value )
116+ else :
117+ request .headers [key ] = value
118+
119+ yield span
120+
121+ with capture_internal_exceptions ():
122+ add_http_request_source (span )
123+
124+ return
125+
86126 with start_span (
87127 op = OP .HTTP_CLIENT ,
88128 name = f"{ request .method } { parsed_url .url if parsed_url else SENSITIVE_DATA_SUBSTITUTE } " ,
@@ -124,7 +164,14 @@ async def sentry_async_middleware(
124164
125165 with _sentry_pyreqwest_span (request ) as span :
126166 response = await next_handler .run (request )
127- span .set_http_status (response .status )
167+ if isinstance (span , StreamedSpan ):
168+ span .status = "error" if response .status >= 400 else "ok"
169+ span .set_attribute (
170+ SPANDATA .HTTP_RESPONSE_STATUS_CODE ,
171+ response .status ,
172+ )
173+ else :
174+ span .set_http_status (response .status )
128175
129176 return response
130177
@@ -137,6 +184,13 @@ def sentry_sync_middleware(
137184
138185 with _sentry_pyreqwest_span (request ) as span :
139186 response = next_handler .run (request )
140- span .set_http_status (response .status )
187+ if isinstance (span , StreamedSpan ):
188+ span .status = "error" if response .status >= 400 else "ok"
189+ span .set_attribute (
190+ SPANDATA .HTTP_RESPONSE_STATUS_CODE ,
191+ response .status ,
192+ )
193+ else :
194+ span .set_http_status (response .status )
141195
142196 return response
0 commit comments