88from sentry_sdk .consts import OP , SPANDATA
99from sentry_sdk .integrations import Integration
1010from sentry_sdk .scope import add_global_event_processor
11+ from sentry_sdk .tracing import Span
12+ from sentry_sdk .traces import StreamedSpan
1113from sentry_sdk .tracing_utils import (
1214 EnvironHeaders ,
1315 should_propagate_trace ,
1416 add_http_request_source ,
17+ has_span_streaming_enabled ,
1518)
1619from sentry_sdk .utils import (
1720 SENSITIVE_DATA_SUBSTITUTE ,
3134 from typing import Dict
3235 from typing import Optional
3336 from typing import List
37+ from typing import Union
3438
3539 from sentry_sdk ._types import Event , Hint
3640
@@ -99,22 +103,46 @@ def putrequest(
99103 with capture_internal_exceptions ():
100104 parsed_url = parse_url (real_url , sanitize = False )
101105
102- span = sentry_sdk .start_span (
103- op = OP .HTTP_CLIENT ,
104- name = "%s %s"
105- % (method , parsed_url .url if parsed_url else SENSITIVE_DATA_SUBSTITUTE ),
106- origin = "auto.http.stdlib.httplib" ,
107- )
108- span .set_data (SPANDATA .HTTP_METHOD , method )
109- if parsed_url is not None :
110- span .set_data ("url" , parsed_url .url )
111- span .set_data (SPANDATA .HTTP_QUERY , parsed_url .query )
112- span .set_data (SPANDATA .HTTP_FRAGMENT , parsed_url .fragment )
106+ span_streaming = has_span_streaming_enabled (client .options )
107+ span : "Union[Span, StreamedSpan]"
108+ if span_streaming :
109+ span = sentry_sdk .traces .start_span (
110+ name = "%s %s"
111+ % (method , parsed_url .url if parsed_url else SENSITIVE_DATA_SUBSTITUTE ),
112+ attributes = {
113+ "sentry.origin" : "auto.http.stdlib.httplib" ,
114+ "sentry.op" : OP .HTTP_CLIENT ,
115+ SPANDATA .HTTP_REQUEST_METHOD : method ,
116+ },
117+ )
118+
119+ if parsed_url is not None :
120+ span .set_attribute (SPANDATA .URL_FULL , parsed_url .url )
121+ span .set_attribute (SPANDATA .URL_QUERY , parsed_url .query )
122+ span .set_attribute (SPANDATA .URL_FRAGMENT , parsed_url .fragment )
123+
124+ set_on_span = span .set_attribute
125+
126+ else :
127+ span = sentry_sdk .start_span (
128+ op = OP .HTTP_CLIENT ,
129+ name = "%s %s"
130+ % (method , parsed_url .url if parsed_url else SENSITIVE_DATA_SUBSTITUTE ),
131+ origin = "auto.http.stdlib.httplib" ,
132+ )
133+
134+ span .set_data (SPANDATA .HTTP_METHOD , method )
135+ if parsed_url is not None :
136+ span .set_data ("url" , parsed_url .url )
137+ span .set_data (SPANDATA .HTTP_QUERY , parsed_url .query )
138+ span .set_data (SPANDATA .HTTP_FRAGMENT , parsed_url .fragment )
139+
140+ set_on_span = span .set_data
113141
114142 # for proxies, these point to the proxy host/port
115143 if tunnel_host :
116- span . set_data (SPANDATA .NETWORK_PEER_ADDRESS , self .host )
117- span . set_data (SPANDATA .NETWORK_PEER_PORT , self .port )
144+ set_on_span (SPANDATA .NETWORK_PEER_ADDRESS , self .host )
145+ set_on_span (SPANDATA .NETWORK_PEER_PORT , self .port )
118146
119147 rv = real_putrequest (self , method , url , * args , ** kwargs )
120148
@@ -145,13 +173,23 @@ def getresponse(self: "HTTPConnection", *args: "Any", **kwargs: "Any") -> "Any":
145173 try :
146174 rv = real_getresponse (self , * args , ** kwargs )
147175
148- span .set_http_status (int (rv .status ))
149- span .set_data ("reason" , rv .reason )
176+ if isinstance (span , StreamedSpan ):
177+ status_code = int (rv .status )
178+ span .status = "error" if status_code >= 400 else "ok"
179+ span .set_attribute ("http.response.status_code" , status_code )
180+ else :
181+ span .set_http_status (int (rv .status ))
182+ span .set_data ("reason" , rv .reason )
150183 finally :
151- span .finish ()
184+ if isinstance (span , StreamedSpan ):
185+ with capture_internal_exceptions ():
186+ add_http_request_source (span )
187+ span .end ()
188+ else :
189+ span .finish ()
152190
153- with capture_internal_exceptions ():
154- add_http_request_source (span )
191+ with capture_internal_exceptions ():
192+ add_http_request_source (span )
155193
156194 return rv
157195
@@ -226,11 +264,24 @@ def sentry_patched_popen_init(
226264
227265 env = None
228266
229- with sentry_sdk .start_span (
230- op = OP .SUBPROCESS ,
231- name = description ,
232- origin = "auto.subprocess.stdlib.subprocess" ,
233- ) as span :
267+ span_streaming = has_span_streaming_enabled (sentry_sdk .get_client ().options )
268+ span : "Union[Span, StreamedSpan]"
269+ if span_streaming :
270+ span = sentry_sdk .traces .start_span (
271+ name = description ,
272+ attributes = {
273+ "sentry.op" : OP .SUBPROCESS ,
274+ "sentry.origin" : "auto.subprocess.stdlib.subprocess" ,
275+ },
276+ )
277+ else :
278+ span = sentry_sdk .start_span (
279+ op = OP .SUBPROCESS ,
280+ name = description ,
281+ origin = "auto.subprocess.stdlib.subprocess" ,
282+ )
283+
284+ with span :
234285 for k , v in sentry_sdk .get_current_scope ().iter_trace_propagation_headers (
235286 span = span
236287 ):
@@ -244,12 +295,16 @@ def sentry_patched_popen_init(
244295 )
245296 env ["SUBPROCESS_" + k .upper ().replace ("-" , "_" )] = v
246297
247- if cwd :
298+ if cwd and isinstance ( span , Span ) :
248299 span .set_data ("subprocess.cwd" , cwd )
249300
250301 rv = old_popen_init (self , * a , ** kw )
251302
252- span .set_tag ("subprocess.pid" , self .pid )
303+ if isinstance (span , StreamedSpan ):
304+ span .set_attribute (SPANDATA .PROCESS_PID , self .pid )
305+ else :
306+ span .set_tag ("subprocess.pid" , self .pid )
307+
253308 return rv
254309
255310 subprocess .Popen .__init__ = sentry_patched_popen_init # type: ignore
@@ -260,12 +315,24 @@ def sentry_patched_popen_init(
260315 def sentry_patched_popen_wait (
261316 self : "subprocess.Popen[Any]" , * a : "Any" , ** kw : "Any"
262317 ) -> "Any" :
263- with sentry_sdk .start_span (
264- op = OP .SUBPROCESS_WAIT ,
265- origin = "auto.subprocess.stdlib.subprocess" ,
266- ) as span :
267- span .set_tag ("subprocess.pid" , self .pid )
268- return old_popen_wait (self , * a , ** kw )
318+ span_streaming = has_span_streaming_enabled (sentry_sdk .get_client ().options )
319+ if span_streaming :
320+ with sentry_sdk .traces .start_span (
321+ name = OP .SUBPROCESS_WAIT ,
322+ attributes = {
323+ "sentry.op" : OP .SUBPROCESS_WAIT ,
324+ "sentry.origin" : "auto.subprocess.stdlib.subprocess" ,
325+ },
326+ ) as span :
327+ span .set_attribute (SPANDATA .PROCESS_PID , self .pid )
328+ return old_popen_wait (self , * a , ** kw )
329+ else :
330+ with sentry_sdk .start_span (
331+ op = OP .SUBPROCESS_WAIT ,
332+ origin = "auto.subprocess.stdlib.subprocess" ,
333+ ) as span :
334+ span .set_tag ("subprocess.pid" , self .pid )
335+ return old_popen_wait (self , * a , ** kw )
269336
270337 subprocess .Popen .wait = sentry_patched_popen_wait # type: ignore
271338
@@ -275,12 +342,24 @@ def sentry_patched_popen_wait(
275342 def sentry_patched_popen_communicate (
276343 self : "subprocess.Popen[Any]" , * a : "Any" , ** kw : "Any"
277344 ) -> "Any" :
278- with sentry_sdk .start_span (
279- op = OP .SUBPROCESS_COMMUNICATE ,
280- origin = "auto.subprocess.stdlib.subprocess" ,
281- ) as span :
282- span .set_tag ("subprocess.pid" , self .pid )
283- return old_popen_communicate (self , * a , ** kw )
345+ span_streaming = has_span_streaming_enabled (sentry_sdk .get_client ().options )
346+ if span_streaming :
347+ with sentry_sdk .traces .start_span (
348+ name = OP .SUBPROCESS_COMMUNICATE ,
349+ attributes = {
350+ "sentry.op" : OP .SUBPROCESS_COMMUNICATE ,
351+ "sentry.origin" : "auto.subprocess.stdlib.subprocess" ,
352+ },
353+ ) as span :
354+ span .set_attribute (SPANDATA .PROCESS_PID , self .pid )
355+ return old_popen_communicate (self , * a , ** kw )
356+ else :
357+ with sentry_sdk .start_span (
358+ op = OP .SUBPROCESS_COMMUNICATE ,
359+ origin = "auto.subprocess.stdlib.subprocess" ,
360+ ) as span :
361+ span .set_tag ("subprocess.pid" , self .pid )
362+ return old_popen_communicate (self , * a , ** kw )
284363
285364 subprocess .Popen .communicate = sentry_patched_popen_communicate # type: ignore
286365
0 commit comments