Skip to content

Commit 9d010bf

Browse files
sentrivanaclaude
andcommitted
fix(tracing): Skip child span creation in streaming path when no current span (databases)
When span streaming is enabled and there is no current span, database integrations should not create new root segments for child-span operations. This adds a guard check using `sentry_sdk.traces.get_current_span()` before creating spans in the streaming path. Affected integrations: aiomysql, asyncpg, clickhouse_driver, pymongo, redis. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 2b9c102 commit 9d010bf

6 files changed

Lines changed: 70 additions & 53 deletions

File tree

sentry_sdk/integrations/aiomysql.py

Lines changed: 20 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -179,33 +179,34 @@ async def _inner(self: "Connection") -> T:
179179
"sentry.origin": AioMySQLIntegration.origin,
180180
} | breadcrumb_data
181181

182+
if sentry_sdk.traces.get_current_span() is None:
183+
return await f(self)
184+
182185
with sentry_sdk.traces.start_span(
183186
name="connect", attributes=span_attributes
184-
) as span:
187+
):
185188
with capture_internal_exceptions():
186189
sentry_sdk.add_breadcrumb(
187190
message="connect", category="query", data=breadcrumb_data
188191
)
189-
res = await f(self)
190-
else:
191-
connect_data = _get_connect_data(self)
192-
193-
with sentry_sdk.start_span(
194-
op=OP.DB,
195-
name="connect",
196-
origin=AioMySQLIntegration.origin,
197-
) as span:
198-
_set_db_data(span, self)
192+
return await f(self)
199193

200-
with capture_internal_exceptions():
201-
sentry_sdk.add_breadcrumb(
202-
message="connect",
203-
category="query",
204-
data=connect_data,
205-
)
206-
res = await f(self)
194+
connect_data = _get_connect_data(self)
207195

208-
return res
196+
with sentry_sdk.start_span(
197+
op=OP.DB,
198+
name="connect",
199+
origin=AioMySQLIntegration.origin,
200+
) as span:
201+
_set_db_data(span, self)
202+
203+
with capture_internal_exceptions():
204+
sentry_sdk.add_breadcrumb(
205+
message="connect",
206+
category="query",
207+
data=connect_data,
208+
)
209+
return await f(self)
209210

210211
return _inner
211212

sentry_sdk/integrations/asyncpg.py

Lines changed: 25 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -235,39 +235,39 @@ async def _inner(*args: "Any", **kwargs: "Any") -> "T":
235235
except IndexError:
236236
pass
237237

238+
if sentry_sdk.traces.get_current_span() is None:
239+
return await f(*args, **kwargs)
240+
238241
with sentry_sdk.traces.start_span(
239242
name="connect", attributes=span_attributes
240-
) as span:
243+
):
241244
with capture_internal_exceptions():
242245
sentry_sdk.add_breadcrumb(
243246
message="connect", category="query", data=span_attributes
244247
)
245-
res = await f(*args, **kwargs)
246-
247-
else:
248-
with sentry_sdk.start_span(
249-
op=OP.DB,
250-
name="connect",
251-
origin=AsyncPGIntegration.origin,
252-
) as span:
253-
span.set_data(SPANDATA.DB_SYSTEM, "postgresql")
254-
if addr:
255-
try:
256-
span.set_data(SPANDATA.SERVER_ADDRESS, addr[0])
257-
span.set_data(SPANDATA.SERVER_PORT, addr[1])
258-
except IndexError:
259-
pass
260-
span.set_data(SPANDATA.DB_NAME, database)
261-
span.set_data(SPANDATA.DB_USER, user)
262-
span.set_data(SPANDATA.DB_DRIVER_NAME, "asyncpg")
248+
return await f(*args, **kwargs)
263249

264-
with capture_internal_exceptions():
265-
sentry_sdk.add_breadcrumb(
266-
message="connect", category="query", data=span._data
267-
)
268-
res = await f(*args, **kwargs)
250+
with sentry_sdk.start_span(
251+
op=OP.DB,
252+
name="connect",
253+
origin=AsyncPGIntegration.origin,
254+
) as span:
255+
span.set_data(SPANDATA.DB_SYSTEM, "postgresql")
256+
if addr:
257+
try:
258+
span.set_data(SPANDATA.SERVER_ADDRESS, addr[0])
259+
span.set_data(SPANDATA.SERVER_PORT, addr[1])
260+
except IndexError:
261+
pass
262+
span.set_data(SPANDATA.DB_NAME, database)
263+
span.set_data(SPANDATA.DB_USER, user)
264+
span.set_data(SPANDATA.DB_DRIVER_NAME, "asyncpg")
269265

270-
return res
266+
with capture_internal_exceptions():
267+
sentry_sdk.add_breadcrumb(
268+
message="connect", category="query", data=span._data
269+
)
270+
return await f(*args, **kwargs)
271271

272272
return _inner
273273

sentry_sdk/integrations/clickhouse_driver.py

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -85,14 +85,16 @@ def _inner(*args: "P.args", **kwargs: "P.kwargs") -> "T":
8585
params = args[3] if len(args) > 3 else kwargs.get("params")
8686

8787
if has_span_streaming_enabled(client.options):
88-
span = sentry_sdk.traces.start_span(
89-
name=query, # type: ignore
90-
attributes={
91-
"sentry.op": OP.DB,
92-
"sentry.origin": ClickhouseDriverIntegration.origin,
93-
SPANDATA.DB_QUERY_TEXT: str(query),
94-
},
95-
)
88+
span = None
89+
if sentry_sdk.traces.get_current_span() is not None:
90+
span = sentry_sdk.traces.start_span(
91+
name=query, # type: ignore
92+
attributes={
93+
"sentry.op": OP.DB,
94+
"sentry.origin": ClickhouseDriverIntegration.origin,
95+
SPANDATA.DB_QUERY_TEXT: str(query),
96+
},
97+
)
9698
else:
9799
span = sentry_sdk.start_span(
98100
op=OP.DB,
@@ -110,7 +112,8 @@ def _inner(*args: "P.args", **kwargs: "P.kwargs") -> "T":
110112

111113
connection._sentry_span = span # type: ignore[attr-defined]
112114

113-
_set_db_data(span, connection)
115+
if span is not None:
116+
_set_db_data(span, connection)
114117

115118
# run the original code
116119
ret = f(*args, **kwargs)

sentry_sdk/integrations/pymongo.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,9 @@ def started(self, event: "CommandStartedEvent") -> None:
152152
query = json.dumps(command, default=str)
153153

154154
if has_span_streaming_enabled(client.options):
155+
if sentry_sdk.traces.get_current_span() is None:
156+
return
157+
155158
span_first_data = {
156159
"db.operation.name": operation_name,
157160
"db.collection.name": collection_name,

sentry_sdk/integrations/redis/_async_common.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,8 @@ async def _sentry_execute(self: "Any", *args: "Any", **kwargs: "Any") -> "Any":
4646

4747
span: "Union[Span, StreamedSpan]"
4848
if span_streaming:
49+
if sentry_sdk.traces.get_current_span() is None:
50+
return await old_execute(self, *args, **kwargs)
4951
span = sentry_sdk.traces.start_span(
5052
name="redis.pipeline.execute",
5153
attributes={
@@ -103,6 +105,9 @@ async def _sentry_execute_command(
103105

104106
span_streaming = has_span_streaming_enabled(client.options)
105107

108+
if span_streaming and sentry_sdk.traces.get_current_span() is None:
109+
return await old_execute_command(self, name, *args, **kwargs)
110+
106111
cache_properties = _compile_cache_span_properties(
107112
name,
108113
args,

sentry_sdk/integrations/redis/_sync_common.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,8 @@ def sentry_patched_execute(self: "Any", *args: "Any", **kwargs: "Any") -> "Any":
4343

4444
span: "Union[Span, StreamedSpan]"
4545
if span_streaming:
46+
if sentry_sdk.traces.get_current_span() is None:
47+
return old_execute(self, *args, **kwargs)
4648
span = sentry_sdk.traces.start_span(
4749
name="redis.pipeline.execute",
4850
attributes={
@@ -102,6 +104,9 @@ def sentry_patched_execute_command(
102104

103105
span_streaming = has_span_streaming_enabled(client.options)
104106

107+
if span_streaming and sentry_sdk.traces.get_current_span() is None:
108+
return old_execute_command(self, name, *args, **kwargs)
109+
105110
cache_properties = _compile_cache_span_properties(
106111
name,
107112
args,

0 commit comments

Comments
 (0)