55
66import sentry_sdk
77from sentry_sdk .consts import SPANTEMPLATE
8- from sentry_sdk .tracing import trace
98from sentry_sdk .tracing_utils import create_span_decorator
109from sentry_sdk .utils import logger
1110from tests .conftest import patch_start_tracing_child
@@ -86,6 +85,246 @@ async def test_trace_decorator_async_no_trx():
8685 assert result2 == "return_of_async_function"
8786
8887
88+ def test_trace_decorator_span_streaming (sentry_init , capture_items ):
89+ sentry_init (
90+ traces_sample_rate = 1.0 ,
91+ _experiments = {"trace_lifecycle" : "stream" },
92+ )
93+
94+ items = capture_items ("span" )
95+
96+ @sentry_sdk .traces .trace
97+ def traced_function ():
98+ return "ok"
99+
100+ result = traced_function ()
101+ assert result == "ok"
102+
103+ sentry_sdk .get_client ().flush ()
104+ spans = [item .payload for item in items ]
105+
106+ assert len (spans ) == 1
107+ (span ,) = spans
108+
109+ assert (
110+ span ["name" ]
111+ == "test_decorator.test_trace_decorator_span_streaming.<locals>.traced_function"
112+ )
113+ assert span ["status" ] == "ok"
114+
115+
116+ def test_trace_decorator_arguments_span_streaming (sentry_init , capture_items ):
117+ sentry_init (
118+ traces_sample_rate = 1.0 ,
119+ _experiments = {"trace_lifecycle" : "stream" },
120+ )
121+
122+ items = capture_items ("span" )
123+
124+ @sentry_sdk .traces .trace (name = "traced" , attributes = {"traced.attribute" : 123 })
125+ def traced_function ():
126+ return "ok"
127+
128+ result = traced_function ()
129+ assert result == "ok"
130+
131+ sentry_sdk .get_client ().flush ()
132+ spans = [item .payload for item in items ]
133+
134+ assert len (spans ) == 1
135+ (span ,) = spans
136+
137+ assert span ["name" ] == "traced"
138+ assert span ["attributes" ]["traced.attribute" ] == 123
139+ assert span ["status" ] == "ok"
140+
141+
142+ def test_trace_decorator_inactive_span_streaming (sentry_init , capture_items ):
143+ sentry_init (
144+ traces_sample_rate = 1.0 ,
145+ _experiments = {"trace_lifecycle" : "stream" },
146+ )
147+
148+ items = capture_items ("span" )
149+
150+ @sentry_sdk .traces .trace (name = "outer" , active = False )
151+ def traced_function ():
152+ with sentry_sdk .traces .start_span (name = "inner" ):
153+ return "ok"
154+
155+ result = traced_function ()
156+ assert result == "ok"
157+
158+ sentry_sdk .get_client ().flush ()
159+ spans = [item .payload for item in items ]
160+
161+ assert len (spans ) == 2
162+ (span1 , span2 ) = spans
163+
164+ assert span1 ["name" ] == "inner"
165+ assert span1 .get ("parent_span_id" ) != span2 ["span_id" ]
166+
167+ assert span2 ["name" ] == "outer"
168+
169+
170+ @pytest .mark .asyncio
171+ async def test_trace_decorator_async_span_streaming (sentry_init , capture_items ):
172+ sentry_init (
173+ traces_sample_rate = 1.0 ,
174+ _experiments = {"trace_lifecycle" : "stream" },
175+ )
176+
177+ items = capture_items ("span" )
178+
179+ @sentry_sdk .traces .trace
180+ async def traced_function ():
181+ return "ok"
182+
183+ result = await traced_function ()
184+ assert result == "ok"
185+
186+ sentry_sdk .get_client ().flush ()
187+ spans = [item .payload for item in items ]
188+
189+ assert len (spans ) == 1
190+ (span ,) = spans
191+
192+ assert (
193+ span ["name" ]
194+ == "test_decorator.test_trace_decorator_async_span_streaming.<locals>.traced_function"
195+ )
196+ assert span ["status" ] == "ok"
197+
198+
199+ @pytest .mark .asyncio
200+ async def test_trace_decorator_async_arguments_span_streaming (
201+ sentry_init , capture_items
202+ ):
203+ sentry_init (
204+ traces_sample_rate = 1.0 ,
205+ _experiments = {"trace_lifecycle" : "stream" },
206+ )
207+
208+ items = capture_items ("span" )
209+
210+ @sentry_sdk .traces .trace (name = "traced" , attributes = {"traced.attribute" : 123 })
211+ async def traced_function ():
212+ return "ok"
213+
214+ result = await traced_function ()
215+ assert result == "ok"
216+
217+ sentry_sdk .get_client ().flush ()
218+ spans = [item .payload for item in items ]
219+
220+ assert len (spans ) == 1
221+ (span ,) = spans
222+
223+ assert span ["name" ] == "traced"
224+ assert span ["attributes" ]["traced.attribute" ] == 123
225+ assert span ["status" ] == "ok"
226+
227+
228+ @pytest .mark .asyncio
229+ async def test_trace_decorator_async_inactive_span_streaming (
230+ sentry_init , capture_items
231+ ):
232+ sentry_init (
233+ traces_sample_rate = 1.0 ,
234+ _experiments = {"trace_lifecycle" : "stream" },
235+ )
236+
237+ items = capture_items ("span" )
238+
239+ @sentry_sdk .traces .trace (name = "outer" , active = False )
240+ async def traced_function ():
241+ with sentry_sdk .traces .start_span (name = "inner" ):
242+ return "ok"
243+
244+ result = await traced_function ()
245+ assert result == "ok"
246+
247+ sentry_sdk .get_client ().flush ()
248+ spans = [item .payload for item in items ]
249+
250+ assert len (spans ) == 2
251+ (span1 , span2 ) = spans
252+
253+ assert span1 ["name" ] == "inner"
254+ assert span1 .get ("parent_span_id" ) != span2 ["span_id" ]
255+
256+ assert span2 ["name" ] == "outer"
257+
258+
259+ def test_trace_decorator_child_span_streaming (sentry_init , capture_items ):
260+ """Spans created with @trace show up as children if a span is active."""
261+ sentry_init (
262+ traces_sample_rate = 1.0 ,
263+ _experiments = {
264+ "trace_lifecycle" : "stream" ,
265+ },
266+ )
267+
268+ items = capture_items ("span" )
269+
270+ @sentry_sdk .traces .trace
271+ def _some_function_traced_stream (a , b , c ):
272+ return True
273+
274+ with sentry_sdk .traces .start_span (name = "segment" ) as segment :
275+ result = _some_function_traced_stream (1 , 2 , 3 )
276+
277+ assert result is True
278+
279+ sentry_sdk .flush ()
280+
281+ assert len (items ) == 2
282+ child_span , segment_span = items [0 ].payload , items [1 ].payload
283+
284+ assert (
285+ child_span ["name" ]
286+ == "test_decorator.test_trace_decorator_child_span_streaming.<locals>._some_function_traced_stream"
287+ )
288+ assert child_span ["parent_span_id" ] == segment .span_id
289+ assert segment_span ["name" ] == "segment"
290+ assert "parent_span_id" not in segment_span
291+
292+
293+ @pytest .mark .asyncio
294+ async def test_trace_decorator_async_child_span_streaming (sentry_init , capture_items ):
295+ """Spans created with @trace show up as children if a span is active."""
296+ sentry_init (
297+ traces_sample_rate = 1.0 ,
298+ _experiments = {
299+ "trace_lifecycle" : "stream" ,
300+ },
301+ )
302+
303+ items = capture_items ("span" )
304+
305+ @sentry_sdk .traces .trace
306+ async def _some_function_traced_stream (a , b , c ):
307+ return True
308+
309+ with sentry_sdk .traces .start_span (name = "segment" ) as segment :
310+ result = await _some_function_traced_stream (1 , 2 , 3 )
311+
312+ assert result is True
313+
314+ sentry_sdk .flush ()
315+
316+ assert len (items ) == 2
317+ child_span , segment_span = items [0 ].payload , items [1 ].payload
318+
319+ assert (
320+ child_span ["name" ]
321+ == "test_decorator.test_trace_decorator_async_child_span_streaming.<locals>._some_function_traced_stream"
322+ )
323+ assert child_span ["parent_span_id" ] == segment .span_id
324+ assert segment_span ["name" ] == "segment"
325+ assert "parent_span_id" not in segment_span
326+
327+
89328def test_functions_to_trace_signature_unchanged_sync (sentry_init ):
90329 sentry_init (
91330 traces_sample_rate = 1.0 ,
@@ -94,14 +333,22 @@ def test_functions_to_trace_signature_unchanged_sync(sentry_init):
94333 def _some_function (a , b , c ):
95334 pass
96335
97- @trace
336+ @sentry_sdk . trace
98337 def _some_function_traced (a , b , c ):
99338 pass
100339
340+ @sentry_sdk .traces .trace
341+ def _some_function_traced_stream (a , b , c ):
342+ pass
343+
101344 assert inspect .getcallargs (_some_function , 1 , 2 , 3 ) == inspect .getcallargs (
102345 _some_function_traced , 1 , 2 , 3
103346 )
104347
348+ assert inspect .getcallargs (_some_function , 1 , 2 , 3 ) == inspect .getcallargs (
349+ _some_function_traced_stream , 1 , 2 , 3
350+ )
351+
105352
106353@pytest .mark .asyncio
107354async def test_functions_to_trace_signature_unchanged_async (sentry_init ):
@@ -112,13 +359,20 @@ async def test_functions_to_trace_signature_unchanged_async(sentry_init):
112359 async def _some_function (a , b , c ):
113360 pass
114361
115- @trace
362+ @sentry_sdk . trace
116363 async def _some_function_traced (a , b , c ):
117364 pass
118365
366+ @sentry_sdk .traces .trace
367+ async def _some_function_traced_stream (a , b , c ):
368+ pass
369+
119370 assert inspect .getcallargs (_some_function , 1 , 2 , 3 ) == inspect .getcallargs (
120371 _some_function_traced , 1 , 2 , 3
121372 )
373+ assert inspect .getcallargs (_some_function , 1 , 2 , 3 ) == inspect .getcallargs (
374+ _some_function_traced_stream , 1 , 2 , 3
375+ )
122376
123377
124378@pytest .mark .parametrize ("stream_gen_ai_spans" , [True , False ])
0 commit comments