1414from sentry_sdk .integrations .boto3 ._instrumentation import _instrument_streaming_body
1515from sentry_sdk .integrations .boto3 .consts import ORIGIN
1616from sentry_sdk .integrations .stdlib import StdlibIntegration
17+ from sentry_sdk .traces import StreamedSpan
18+ from sentry_sdk .tracing import Span
1719from tests .integrations .boto3 .aws_mock import Body
1820
1921session = boto3 .Session ( # type: ignore[attr-defined]
@@ -53,15 +55,17 @@ def log_message(self, *args):
5355 "consume" ,
5456 ["read" , "read_exact" , "context" , "close" ],
5557)
58+ @pytest .mark .parametrize ("span_streaming" , [True , False ])
5659def test_streaming_span_order_and_scope (
5760 sentry_init ,
5861 capture_items ,
5962 streaming_s3_server ,
6063 consume ,
64+ span_streaming ,
6165):
6266 sentry_init (
6367 traces_sample_rate = 1.0 ,
64- trace_lifecycle = "stream" ,
68+ trace_lifecycle = "stream" if span_streaming else "static" ,
6569 default_integrations = False ,
6670 integrations = [Boto3Integration (), StdlibIntegration ()],
6771 server_name = "" ,
@@ -75,11 +79,31 @@ def test_streaming_span_order_and_scope(
7579 s3 = {"addressing_style" : "path" },
7680 ),
7781 )
78- items = capture_items ( "span" )
82+ request_client_spans = []
7983
80- with sentry_sdk .traces .start_span (name = "parent" ) as parent : # type: ignore[attr-defined]
84+ def record_client_span (request , ** kwargs ):
85+ request_client_spans .append (request .context ["_sentrysdk_span" ])
86+
87+ client .meta .events .register ("request-created" , record_client_span )
88+ items = capture_items ()
89+
90+ parent_context = (
91+ sentry_sdk .traces .start_span (name = "parent" ) # type: ignore[attr-defined]
92+ if span_streaming
93+ else sentry_sdk .start_transaction (name = "parent" )
94+ )
95+ with parent_context as parent :
8196 body = client .get_object (Bucket = "bucket" , Key = "key" )["Body" ]
82- assert sentry_sdk .traces .get_current_span () is parent # type: ignore[attr-defined]
97+ assert len (request_client_spans ) == 1
98+ request_client_span = request_client_spans [0 ]
99+ if span_streaming :
100+ assert isinstance (request_client_span , StreamedSpan )
101+ assert request_client_span .end_timestamp is None
102+ assert sentry_sdk .traces .get_current_span () is parent # type: ignore[attr-defined]
103+ else :
104+ assert isinstance (request_client_span , Span )
105+ assert not isinstance (request_client_span , StreamedSpan )
106+ assert request_client_span .timestamp is None
83107
84108 if consume == "read" :
85109 assert body .read () == b"x"
@@ -94,34 +118,54 @@ def test_streaming_span_order_and_scope(
94118 else :
95119 body .close ()
96120
97- assert sentry_sdk .traces .get_current_span () is parent # type: ignore[attr-defined]
121+ if span_streaming :
122+ assert request_client_span .end_timestamp is not None
123+ assert sentry_sdk .traces .get_current_span () is parent # type: ignore[attr-defined]
98124
99- probe = sentry_sdk .traces .start_span (name = "probe" ) # type: ignore[attr-defined]
100- assert probe ._parent_span_id == parent .span_id
101- probe .end ()
125+ probe = sentry_sdk .traces .start_span (name = "probe" ) # type: ignore[attr-defined]
126+ assert probe ._parent_span_id == parent .span_id
127+ probe .end ()
102128
103- body .close ()
104- assert sentry_sdk .traces .get_current_span () is parent # type: ignore[attr-defined]
129+ body .close ()
130+ assert sentry_sdk .traces .get_current_span () is parent # type: ignore[attr-defined]
131+ else :
132+ assert request_client_span .timestamp is not None
105133
106134 sentry_sdk .flush ()
107- spans = [item .payload for item in items ]
135+ if span_streaming :
136+ spans = [item .payload for item in items ]
137+ else :
138+ transaction = next (item .payload for item in items if item .type == "transaction" )
139+ spans = transaction ["spans" ]
108140 client_spans = [
109141 span
110142 for span in spans
111- if span ["name" ] == "aws.s3.GetObject"
112- and span ["attributes" ].get (SPANDATA .SENTRY_ORIGIN ) == ORIGIN
113- and span ["attributes" ].get (SPANDATA .SENTRY_OP ) == OP .HTTP_CLIENT
143+ if span .get ("name" , span .get ("description" )) == "aws.s3.GetObject"
144+ and (
145+ span ["attributes" ].get (SPANDATA .SENTRY_ORIGIN ) == ORIGIN
146+ and span ["attributes" ].get (SPANDATA .SENTRY_OP ) == OP .HTTP_CLIENT
147+ if span_streaming
148+ else span ["origin" ] == ORIGIN and span ["op" ] == OP .HTTP_CLIENT
149+ )
114150 ]
115151 http_spans = [
116152 span
117153 for span in spans
118- if span ["attributes" ].get (SPANDATA .SENTRY_ORIGIN ) == "auto.http.stdlib.httplib"
154+ if (
155+ span ["attributes" ].get (SPANDATA .SENTRY_ORIGIN ) == "auto.http.stdlib.httplib"
156+ if span_streaming
157+ else span ["origin" ] == "auto.http.stdlib.httplib"
158+ )
119159 ]
120160 stream_spans = [
121161 span
122162 for span in spans
123- if span ["name" ] == "aws.s3.GetObject"
124- and span ["attributes" ].get (SPANDATA .SENTRY_OP ) == OP .HTTP_CLIENT_STREAM
163+ if span .get ("name" , span .get ("description" )) == "aws.s3.GetObject"
164+ and (
165+ span ["attributes" ].get (SPANDATA .SENTRY_OP ) == OP .HTTP_CLIENT_STREAM
166+ if span_streaming
167+ else span ["op" ] == OP .HTTP_CLIENT_STREAM
168+ )
125169 ]
126170 assert len (client_spans ) == 1
127171 assert len (http_spans ) == 1
@@ -132,10 +176,12 @@ def test_streaming_span_order_and_scope(
132176
133177 assert http_span ["parent_span_id" ] == client_span ["span_id" ]
134178 assert stream_span ["parent_span_id" ] == client_span ["span_id" ]
179+ assert client_span ["span_id" ] == request_client_span .span_id
180+ end_timestamp = "end_timestamp" if span_streaming else "timestamp"
135181 assert client_span ["start_timestamp" ] <= http_span ["start_timestamp" ]
136182 assert http_span ["start_timestamp" ] <= stream_span ["start_timestamp" ]
137- assert http_span [" end_timestamp" ] <= stream_span [" end_timestamp" ]
138- assert stream_span [" end_timestamp" ] <= client_span [" end_timestamp" ]
183+ assert http_span [end_timestamp ] <= stream_span [end_timestamp ]
184+ assert stream_span [end_timestamp ] <= client_span [end_timestamp ]
139185
140186
141187@pytest .mark .parametrize ("span_streaming" , [True , False ])
@@ -437,7 +483,5 @@ def invoke_client_method_and_read_body():
437483 client_spans = spans_by_op .get (OP .HTTP_CLIENT , [])
438484 stream_spans = spans_by_op .get (OP .HTTP_CLIENT_STREAM , [])
439485
440- assert len (client_spans ) == 1
441- if span_streaming :
442- _assert_one_failed_span (client_spans , span_streaming = True )
486+ _assert_one_failed_span (client_spans , span_streaming )
443487 _assert_one_failed_span (stream_spans , span_streaming )
0 commit comments