@@ -102,6 +102,7 @@ def start_span(
102102 name : str ,
103103 attributes : "Optional[Attributes]" = None ,
104104 parent_span : "Optional[StreamedSpan]" = None ,
105+ active : bool = True ,
105106) -> "StreamedSpan" :
106107 """
107108 Start a span.
@@ -136,19 +137,28 @@ def start_span(
136137
137138 :param name: The name to identify this span by.
138139 :type name: str
140+
139141 :param attributes: Key-value attributes to set on the span from the start.
140142 When provided via the `start_span()` function, these will also be
141143 accessible in the traces sampler.
142144 :type attributes: "Optional[Attributes]"
145+
143146 :param parent_span: A span instance that the new span should be parented to.
144147 If not provided, the parent will be set to the currently active span,
145148 if any.
146149 :type parent_span: "Optional[StreamedSpan]"
150+
151+ :param active: Controls whether spans started while this span is running
152+ will automatically become its children. That's the default behavior. If
153+ you want to create a span that shouldn't have any children (unless
154+ provided explicitly via the `parent_span` argument), set this to False.
155+ :type active: bool
156+
147157 :return: A span.
148158 :rtype: StreamedSpan
149159 """
150160 return sentry_sdk .get_current_scope ().start_streamed_span (
151- name , attributes , parent_span
161+ name , attributes , parent_span , active
152162 )
153163
154164
@@ -201,6 +211,7 @@ class StreamedSpan:
201211 __slots__ = (
202212 "_name" ,
203213 "_attributes" ,
214+ "_active" ,
204215 "_span_id" ,
205216 "_trace_id" ,
206217 "parent_span_id" ,
@@ -227,6 +238,7 @@ def __init__(
227238 name : str ,
228239 scope : "sentry_sdk.Scope" ,
229240 attributes : "Optional[Attributes]" = None ,
241+ active : bool = True ,
230242 # TODO[span-first]: would be good to actually take this propagation
231243 # context stuff directly from the PropagationContext, but for that
232244 # we'd actually need to refactor PropagationContext to stay in sync
@@ -241,6 +253,7 @@ def __init__(
241253 last_valid_parent_id : "Optional[str]" = None ,
242254 ) -> None :
243255 self ._scope = scope
256+ self ._active = active
244257
245258 self ._name : str = name
246259 self ._attributes : "Attributes" = {}
@@ -295,14 +308,16 @@ def __repr__(self) -> str:
295308 f"trace_id={ self .trace_id } , "
296309 f"span_id={ self .span_id } , "
297310 f"parent_span_id={ self .parent_span_id } , "
298- f"sampled={ self .sampled } )>"
311+ f"sampled={ self .sampled } , "
312+ f"active={ self ._active } )>"
299313 )
300314
301315 def __enter__ (self ) -> "StreamedSpan" :
302316 scope = self ._scope or sentry_sdk .get_current_scope ()
303- old_span = scope .span
304- scope .span = self
305- self ._context_manager_state = (scope , old_span )
317+ if self ._active :
318+ old_span = scope .span
319+ scope .span = self
320+ self ._context_manager_state = (scope , old_span )
306321
307322 if self .is_segment ():
308323 sampling_context = {
@@ -338,11 +353,15 @@ def __exit__(
338353 if value is not None and should_be_treated_as_error (ty , value ):
339354 self .set_status (SpanStatus .ERROR )
340355
341- with capture_internal_exceptions ():
342- scope , old_span = self ._context_manager_state
343- del self ._context_manager_state
344- self ._end (scope = scope )
345- scope .span = old_span
356+ if self ._active :
357+ with capture_internal_exceptions ():
358+ scope , old_span = self ._context_manager_state
359+ del self ._context_manager_state
360+ scope .span = old_span
361+ else :
362+ scope = self ._scope
363+
364+ self ._end (scope = self ._scope )
346365
347366 def start (self ) -> "StreamedSpan" :
348367 """
@@ -761,6 +780,7 @@ def trace(
761780 * ,
762781 name : "Optional[str]" = None ,
763782 attributes : "Optional[dict[str, Any]]" = None ,
783+ active : bool = True ,
764784) -> "Union[Callable[P, R], Callable[[Callable[P, R]], Callable[P, R]]]" :
765785 """
766786 Decorator to start a span around a function call.
@@ -783,6 +803,12 @@ def trace(
783803 attributes provide additional context about the span's execution.
784804 :type attributes: dict[str, Any] or None
785805
806+ :param active: Controls whether spans started while this span is running
807+ will automatically become its children. That's the default behavior. If
808+ you want to create a span that shouldn't have any children (unless
809+ provided explicitly via the `parent_span` argument), set this to False.
810+ :type active: bool
811+
786812 :returns: When used as ``@trace``, returns the decorated function. When used as
787813 ``@trace(...)`` with parameters, returns a decorator function.
788814 :rtype: Callable or decorator function
@@ -811,6 +837,7 @@ def make_db_query(sql):
811837 decorator = create_streaming_span_decorator (
812838 name = name ,
813839 attributes = attributes ,
840+ active = active ,
814841 )
815842
816843 if func :
0 commit comments