Skip to content

Commit 2b6ba2d

Browse files
committed
Merge branch 'ivana/streaming-child-spans-web-frameworks' of github.com:getsentry/sentry-python into ivana/streaming-child-spans-web-frameworks
2 parents eccbb24 + 8af72d8 commit 2b6ba2d

18 files changed

Lines changed: 358 additions & 121 deletions

File tree

sentry_sdk/client.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -382,6 +382,12 @@ def _get_options(*args: "Optional[str]", **kwargs: "Any") -> "Dict[str, Any]":
382382
stacklevel=2,
383383
)
384384

385+
if rv["ignore_spans"] and not has_span_streaming_enabled(rv):
386+
warnings.warn(
387+
"The `ignore_spans` parameter only works when `trace_lifecycle` is set to `stream`.",
388+
stacklevel=2,
389+
)
390+
385391
return rv
386392

387393

sentry_sdk/consts.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1272,6 +1272,7 @@ def __init__(
12721272
server_name: "Optional[str]" = None,
12731273
shutdown_timeout: float = 2,
12741274
integrations: "Sequence[sentry_sdk.integrations.Integration]" = [], # noqa: B006
1275+
ignore_spans: "Optional[IgnoreSpansConfig]" = None,
12751276
in_app_include: "List[str]" = [], # noqa: B006
12761277
in_app_exclude: "List[str]" = [], # noqa: B006
12771278
default_integrations: bool = True,
@@ -1293,6 +1294,7 @@ def __init__(
12931294
ca_certs: "Optional[str]" = None,
12941295
propagate_traces: bool = True,
12951296
traces_sample_rate: "Optional[float]" = None,
1297+
trace_lifecycle: "Optional[Literal['static', 'stream']]" = None,
12961298
traces_sampler: "Optional[TracesSampler]" = None,
12971299
profiles_sample_rate: "Optional[float]" = None,
12981300
profiles_sampler: "Optional[TracesSampler]" = None,
@@ -1757,6 +1759,12 @@ def __init__(
17571759
:param stream_gen_ai_spans: When set, generative AI spans are sent in a new transport format to
17581760
reduce downstream data loss.
17591761
1762+
:param trace_lifecycle: Controls how traces are sent. Set to `"stream"` to send spans as they
1763+
finish, or `"static"` to send a completed trace as a transaction event.
1764+
1765+
:param ignore_spans: A sequence of span-matching rules. Matching spans are ignored when
1766+
`trace_lifecycle="stream"` is enabled.
1767+
17601768
:param _experiments: Dictionary of experimental, opt-in features that are not yet stable.
17611769
17621770
``data_collection`` (EXPERIMENTAL): structured configuration controlling what data integrations

sentry_sdk/integrations/django/__init__.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -724,6 +724,8 @@ def connect(self: "BaseDatabaseWrapper") -> None:
724724

725725
span_streaming = has_span_streaming_enabled(sentry_sdk.get_client().options)
726726
if span_streaming:
727+
if sentry_sdk.traces.get_current_span() is None:
728+
return real_connect(self)
727729
with sentry_sdk.traces.start_span(
728730
name="connect",
729731
attributes={
@@ -750,6 +752,8 @@ def _commit(self: "BaseDatabaseWrapper") -> None:
750752

751753
span_streaming = has_span_streaming_enabled(sentry_sdk.get_client().options)
752754
if span_streaming:
755+
if sentry_sdk.traces.get_current_span() is None:
756+
return real_commit(self)
753757
with sentry_sdk.traces.start_span(
754758
name=SPANNAME.DB_COMMIT,
755759
attributes={
@@ -776,6 +780,8 @@ def _rollback(self: "BaseDatabaseWrapper") -> None:
776780

777781
span_streaming = has_span_streaming_enabled(sentry_sdk.get_client().options)
778782
if span_streaming:
783+
if sentry_sdk.traces.get_current_span() is None:
784+
return real_rollback(self)
779785
with sentry_sdk.traces.start_span(
780786
name=SPANNAME.DB_ROLLBACK,
781787
attributes={

sentry_sdk/integrations/django/asgi.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,8 @@ async def sentry_wrapped_callback(
191191
return await callback(request, *args, **kwargs)
192192

193193
if span_streaming:
194+
if sentry_sdk.traces.get_current_span() is None:
195+
return await callback(request, *args, **kwargs)
194196
with sentry_sdk.traces.start_span(
195197
name=request.resolver_match.view_name,
196198
attributes={

sentry_sdk/integrations/django/caching.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,8 @@ def _instrument_call(
6161

6262
span_streaming = has_span_streaming_enabled(sentry_sdk.get_client().options)
6363
if span_streaming:
64+
if sentry_sdk.traces.get_current_span() is None:
65+
return original_method(*args, **kwargs)
6466
with sentry_sdk.traces.start_span(
6567
name=description,
6668
attributes={

sentry_sdk/integrations/django/middleware.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,8 @@ def _check_middleware_span(
8484
span_streaming = has_span_streaming_enabled(sentry_sdk.get_client().options)
8585
middleware_span: "Union[Span, StreamedSpan]"
8686
if span_streaming:
87+
if sentry_sdk.traces.get_current_span() is None:
88+
return None
8789
middleware_span = sentry_sdk.traces.start_span(
8890
name=description,
8991
attributes={

sentry_sdk/integrations/django/signals_handlers.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,14 +68,16 @@ def wrapper(*args: "Any", **kwargs: "Any") -> "Any":
6868
sentry_sdk.get_client().options
6969
)
7070
if span_streaming:
71+
if sentry_sdk.traces.get_current_span() is None:
72+
return receiver(*args, **kwargs)
7173
with sentry_sdk.traces.start_span(
7274
name=signal_name,
7375
attributes={
7476
"sentry.op": OP.EVENT_DJANGO,
7577
"sentry.origin": DjangoIntegration.origin,
7678
SPANDATA.CODE_FUNCTION_NAME: signal_name,
7779
},
78-
) as span:
80+
):
7981
return receiver(*args, **kwargs)
8082
else:
8183
with sentry_sdk.start_span(

sentry_sdk/integrations/django/tasks.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@ def _sentry_enqueue(self: "Any", *args: "Any", **kwargs: "Any") -> "Any":
3535

3636
span_streaming = has_span_streaming_enabled(sentry_sdk.get_client().options)
3737
if span_streaming:
38+
if sentry_sdk.traces.get_current_span() is None:
39+
return old_task_enqueue(self, *args, **kwargs)
3840
with sentry_sdk.traces.start_span(
3941
name=name,
4042
attributes={

sentry_sdk/integrations/django/templates.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -64,13 +64,15 @@ def patch_templates() -> None:
6464
def rendered_content(self: "SimpleTemplateResponse") -> str:
6565
span_streaming = has_span_streaming_enabled(sentry_sdk.get_client().options)
6666
if span_streaming:
67+
if sentry_sdk.traces.get_current_span() is None:
68+
return real_rendered_content.fget(self)
6769
with sentry_sdk.traces.start_span(
6870
name=_get_template_name_description(self.template_name),
6971
attributes={
7072
"sentry.op": OP.TEMPLATE_RENDER,
7173
"sentry.origin": DjangoIntegration.origin,
7274
},
73-
) as span:
75+
):
7476
return real_rendered_content.fget(self)
7577
else:
7678
with sentry_sdk.start_span(
@@ -109,13 +111,15 @@ def render(
109111
span_streaming = has_span_streaming_enabled(client.options)
110112

111113
if span_streaming:
114+
if sentry_sdk.traces.get_current_span() is None:
115+
return real_render(request, template_name, context, *args, **kwargs)
112116
with sentry_sdk.traces.start_span(
113117
name=_get_template_name_description(template_name),
114118
attributes={
115119
"sentry.op": OP.TEMPLATE_RENDER,
116120
"sentry.origin": DjangoIntegration.origin,
117121
},
118-
) as span:
122+
):
119123
return real_render(request, template_name, context, *args, **kwargs)
120124
else:
121125
with sentry_sdk.start_span(

sentry_sdk/integrations/django/views.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@ def patch_views() -> None:
3434
def sentry_patched_render(self: "SimpleTemplateResponse") -> "Any":
3535
span_streaming = has_span_streaming_enabled(sentry_sdk.get_client().options)
3636
if span_streaming:
37+
if sentry_sdk.traces.get_current_span() is None:
38+
return old_render(self)
3739
with sentry_sdk.traces.start_span(
3840
name="serialize response",
3941
attributes={
@@ -108,6 +110,8 @@ def sentry_wrapped_callback(request: "Any", *args: "Any", **kwargs: "Any") -> "A
108110
return callback(request, *args, **kwargs)
109111

110112
if span_streaming:
113+
if sentry_sdk.traces.get_current_span() is None:
114+
return callback(request, *args, **kwargs)
111115
with sentry_sdk.traces.start_span(
112116
name=request.resolver_match.view_name,
113117
attributes={

0 commit comments

Comments
 (0)