Skip to content

Commit 632dc68

Browse files
authored
Add only_if_parent option to POTelSpan and use it in integrations (#3748)
If this option is on, we will only create a new underlying otel span if there's an active valid parent, otherwise we will just return an invalid `NonRecordingSpan` (`INVALID_SPAN`). All internal integration child `start_span` calls have been modified so that now we will only create spans if there is an active root span (transaction) active.
1 parent 4650c7e commit 632dc68

36 files changed

+98
-23
lines changed

sentry_sdk/ai/monitoring.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,9 @@ def sync_wrapped(*args, **kwargs):
3333
curr_pipeline = _ai_pipeline_name.get()
3434
op = span_kwargs.get("op", "ai.run" if curr_pipeline else "ai.pipeline")
3535

36-
with start_span(name=description, op=op, **span_kwargs) as span:
36+
with start_span(
37+
name=description, op=op, only_if_parent=True, **span_kwargs
38+
) as span:
3739
for k, v in kwargs.pop("sentry_tags", {}).items():
3840
span.set_tag(k, v)
3941
for k, v in kwargs.pop("sentry_data", {}).items():
@@ -62,7 +64,9 @@ async def async_wrapped(*args, **kwargs):
6264
curr_pipeline = _ai_pipeline_name.get()
6365
op = span_kwargs.get("op", "ai.run" if curr_pipeline else "ai.pipeline")
6466

65-
with start_span(name=description, op=op, **span_kwargs) as span:
67+
with start_span(
68+
name=description, op=op, only_if_parent=True, **span_kwargs
69+
) as span:
6670
for k, v in kwargs.pop("sentry_tags", {}).items():
6771
span.set_tag(k, v)
6872
for k, v in kwargs.pop("sentry_data", {}).items():

sentry_sdk/integrations/aiohttp.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -228,6 +228,7 @@ async def on_request_start(session, trace_config_ctx, params):
228228
name="%s %s"
229229
% (method, parsed_url.url if parsed_url else SENSITIVE_DATA_SUBSTITUTE),
230230
origin=AioHttpIntegration.origin,
231+
only_if_parent=True,
231232
)
232233

233234
data = {

sentry_sdk/integrations/anthropic.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,7 @@ def _sentry_patched_create_common(f, *args, **kwargs):
151151
op=OP.ANTHROPIC_MESSAGES_CREATE,
152152
description="Anthropic messages create",
153153
origin=AnthropicIntegration.origin,
154+
only_if_parent=True,
154155
)
155156
span.__enter__()
156157

sentry_sdk/integrations/arq.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,10 @@ async def _sentry_enqueue_job(self, function, *args, **kwargs):
7979
return await old_enqueue_job(self, function, *args, **kwargs)
8080

8181
with sentry_sdk.start_span(
82-
op=OP.QUEUE_SUBMIT_ARQ, name=function, origin=ArqIntegration.origin
82+
op=OP.QUEUE_SUBMIT_ARQ,
83+
name=function,
84+
origin=ArqIntegration.origin,
85+
only_if_parent=True,
8386
):
8487
return await old_enqueue_job(self, function, *args, **kwargs)
8588

sentry_sdk/integrations/asyncio.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ async def _coro_creating_hub_and_span():
4848
op=OP.FUNCTION,
4949
name=get_name(coro),
5050
origin=AsyncioIntegration.origin,
51+
only_if_parent=True,
5152
):
5253
try:
5354
result = await coro

sentry_sdk/integrations/asyncpg.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,7 @@ async def _inner(*args: Any, **kwargs: Any) -> T:
169169
op=OP.DB,
170170
name="connect",
171171
origin=AsyncPGIntegration.origin,
172+
only_if_parent=True,
172173
) as span:
173174
data = _get_db_data(
174175
addr=kwargs.get("addr"),

sentry_sdk/integrations/boto3.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ def _sentry_request_created(service_id, request, operation_name, **kwargs):
7272
op=OP.HTTP_CLIENT,
7373
name=description,
7474
origin=Boto3Integration.origin,
75+
only_if_parent=True,
7576
)
7677

7778
data = {

sentry_sdk/integrations/celery/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -495,6 +495,7 @@ def sentry_publish(self, *args, **kwargs):
495495
op=OP.QUEUE_PUBLISH,
496496
name=task_name,
497497
origin=CeleryIntegration.origin,
498+
only_if_parent=True,
498499
) as span:
499500
if task_id is not None:
500501
span.set_data(SPANDATA.MESSAGING_MESSAGE_ID, task_id)

sentry_sdk/integrations/clickhouse_driver.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@ def _inner(*args: P.args, **kwargs: P.kwargs) -> T:
8989
op=OP.DB,
9090
name=query,
9191
origin=ClickhouseDriverIntegration.origin,
92+
only_if_parent=True,
9293
)
9394

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

sentry_sdk/integrations/cohere.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,7 @@ def new_chat(*args, **kwargs):
147147
op=consts.OP.COHERE_CHAT_COMPLETIONS_CREATE,
148148
name="cohere.client.Chat",
149149
origin=CohereIntegration.origin,
150+
only_if_parent=True,
150151
)
151152
span.__enter__()
152153
try:
@@ -233,6 +234,7 @@ def new_embed(*args, **kwargs):
233234
op=consts.OP.COHERE_EMBEDDINGS_CREATE,
234235
name="Cohere Embedding Creation",
235236
origin=CohereIntegration.origin,
237+
only_if_parent=True,
236238
) as span:
237239
if "texts" in kwargs and (
238240
should_send_default_pii() and integration.include_prompts

sentry_sdk/integrations/django/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -687,6 +687,7 @@ def connect(self):
687687
op=OP.DB,
688688
name="connect",
689689
origin=DjangoIntegration.origin_db,
690+
only_if_parent=True,
690691
) as span:
691692
_set_db_data(span, self)
692693
return real_connect(self)

sentry_sdk/integrations/django/asgi.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,7 @@ async def sentry_wrapped_callback(request, *args, **kwargs):
184184
op=OP.VIEW_RENDER,
185185
name=request.resolver_match.view_name,
186186
origin=DjangoIntegration.origin,
187+
only_if_parent=True,
187188
):
188189
return await callback(request, *args, **kwargs)
189190

sentry_sdk/integrations/django/caching.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ def _instrument_call(
5454
op=op,
5555
name=description,
5656
origin=DjangoIntegration.origin,
57+
only_if_parent=True,
5758
) as span:
5859
value = original_method(*args, **kwargs)
5960

sentry_sdk/integrations/django/middleware.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@ def _check_middleware_span(old_method):
8989
op=OP.MIDDLEWARE_DJANGO,
9090
name=description,
9191
origin=DjangoIntegration.origin,
92+
only_if_parent=True,
9293
)
9394
middleware_span.set_tag("django.function_name", function_name)
9495
middleware_span.set_tag("django.middleware_name", middleware_name)

sentry_sdk/integrations/django/signals_handlers.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ def wrapper(*args, **kwargs):
6868
op=OP.EVENT_DJANGO,
6969
name=signal_name,
7070
origin=DjangoIntegration.origin,
71+
only_if_parent=True,
7172
) as span:
7273
span.set_data("signal", signal_name)
7374
return receiver(*args, **kwargs)

sentry_sdk/integrations/django/templates.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ def rendered_content(self):
7272
op=OP.TEMPLATE_RENDER,
7373
name=_get_template_name_description(self.template_name),
7474
origin=DjangoIntegration.origin,
75+
only_if_parent=True,
7576
) as span:
7677
if isinstance(self.context_data, dict):
7778
for k, v in self.context_data.items():
@@ -102,6 +103,7 @@ def render(request, template_name, context=None, *args, **kwargs):
102103
op=OP.TEMPLATE_RENDER,
103104
name=_get_template_name_description(template_name),
104105
origin=DjangoIntegration.origin,
106+
only_if_parent=True,
105107
) as span:
106108
for k, v in context.items():
107109
span.set_data(f"context.{k}", v)

sentry_sdk/integrations/django/views.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ def sentry_patched_render(self):
3737
op=OP.VIEW_RESPONSE_RENDER,
3838
name="serialize response",
3939
origin=DjangoIntegration.origin,
40+
only_if_parent=True,
4041
):
4142
return old_render(self)
4243

@@ -90,6 +91,7 @@ def sentry_wrapped_callback(request, *args, **kwargs):
9091
op=OP.VIEW_RENDER,
9192
name=request.resolver_match.view_name,
9293
origin=DjangoIntegration.origin,
94+
only_if_parent=True,
9395
):
9496
return callback(request, *args, **kwargs)
9597

sentry_sdk/integrations/graphene.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,9 @@ def graphql_span(schema, source, kwargs):
144144
if scope.span:
145145
_graphql_span = scope.span.start_child(op=op, name=operation_name)
146146
else:
147-
_graphql_span = sentry_sdk.start_span(op=op, name=operation_name)
147+
_graphql_span = sentry_sdk.start_span(
148+
op=op, name=operation_name, only_if_parent=True
149+
)
148150

149151
_graphql_span.set_data("graphql.document", source)
150152
_graphql_span.set_data("graphql.operation.name", operation_name)

sentry_sdk/integrations/grpc/aio/client.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ async def intercept_unary_unary(
5252
op=OP.GRPC_CLIENT,
5353
name="unary unary call to %s" % method.decode(),
5454
origin=SPAN_ORIGIN,
55+
only_if_parent=True,
5556
) as span:
5657
span.set_data("type", "unary unary")
5758
span.set_data("method", method)
@@ -82,6 +83,7 @@ async def intercept_unary_stream(
8283
op=OP.GRPC_CLIENT,
8384
name="unary stream call to %s" % method.decode(),
8485
origin=SPAN_ORIGIN,
86+
only_if_parent=True,
8587
) as span:
8688
span.set_data("type", "unary stream")
8789
span.set_data("method", method)

sentry_sdk/integrations/grpc/client.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ def intercept_unary_unary(self, continuation, client_call_details, request):
3131
op=OP.GRPC_CLIENT,
3232
name="unary unary call to %s" % method,
3333
origin=SPAN_ORIGIN,
34+
only_if_parent=True,
3435
) as span:
3536
span.set_data("type", "unary unary")
3637
span.set_data("method", method)
@@ -52,6 +53,7 @@ def intercept_unary_stream(self, continuation, client_call_details, request):
5253
op=OP.GRPC_CLIENT,
5354
name="unary stream call to %s" % method,
5455
origin=SPAN_ORIGIN,
56+
only_if_parent=True,
5557
) as span:
5658
span.set_data("type", "unary stream")
5759
span.set_data("method", method)

sentry_sdk/integrations/httpx.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ def send(self, request, **kwargs):
5959
parsed_url.url if parsed_url else SENSITIVE_DATA_SUBSTITUTE,
6060
),
6161
origin=HttpxIntegration.origin,
62+
only_if_parent=True,
6263
) as span:
6364
data = {
6465
SPANDATA.HTTP_METHOD: request.method,
@@ -129,6 +130,7 @@ async def send(self, request, **kwargs):
129130
parsed_url.url if parsed_url else SENSITIVE_DATA_SUBSTITUTE,
130131
),
131132
origin=HttpxIntegration.origin,
133+
only_if_parent=True,
132134
) as span:
133135
data = {
134136
SPANDATA.HTTP_METHOD: request.method,

sentry_sdk/integrations/huey.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ def _sentry_enqueue(self, task):
6161
op=OP.QUEUE_SUBMIT_HUEY,
6262
name=task.name,
6363
origin=HueyIntegration.origin,
64+
only_if_parent=True,
6465
):
6566
if not isinstance(task, PeriodicTask):
6667
# Attach trace propagation data to task kwargs. We do

sentry_sdk/integrations/huggingface_hub.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ def new_text_generation(*args, **kwargs):
7777
op=consts.OP.HUGGINGFACE_HUB_CHAT_COMPLETIONS_CREATE,
7878
name="Text Generation",
7979
origin=HuggingfaceHubIntegration.origin,
80+
only_if_parent=True,
8081
)
8182
span.__enter__()
8283
try:

sentry_sdk/integrations/langchain.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,9 @@ def _create_span(self, run_id, parent_id, **kwargs):
143143
watched_span = WatchedSpan(parent_span.span.start_child(**kwargs))
144144
parent_span.children.append(watched_span)
145145
if watched_span is None:
146-
watched_span = WatchedSpan(sentry_sdk.start_span(**kwargs))
146+
watched_span = WatchedSpan(
147+
sentry_sdk.start_span(only_if_parent=True, **kwargs)
148+
)
147149

148150
if kwargs.get("op", "").startswith("ai.pipeline."):
149151
if kwargs.get("name"):

sentry_sdk/integrations/litestar.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,7 @@ async def _create_span_call(self, scope, receive, send):
141141
op=OP.MIDDLEWARE_LITESTAR,
142142
name=middleware_name,
143143
origin=LitestarIntegration.origin,
144+
only_if_parent=True,
144145
) as middleware_span:
145146
middleware_span.set_tag("litestar.middleware_name", middleware_name)
146147

@@ -153,6 +154,7 @@ async def _sentry_receive(*args, **kwargs):
153154
op=OP.MIDDLEWARE_LITESTAR_RECEIVE,
154155
name=getattr(receive, "__qualname__", str(receive)),
155156
origin=LitestarIntegration.origin,
157+
only_if_parent=True,
156158
) as span:
157159
span.set_tag("litestar.middleware_name", middleware_name)
158160
return await receive(*args, **kwargs)
@@ -170,6 +172,7 @@ async def _sentry_send(message):
170172
op=OP.MIDDLEWARE_LITESTAR_SEND,
171173
name=getattr(send, "__qualname__", str(send)),
172174
origin=LitestarIntegration.origin,
175+
only_if_parent=True,
173176
) as span:
174177
span.set_tag("litestar.middleware_name", middleware_name)
175178
return await send(message)

sentry_sdk/integrations/openai.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,7 @@ def _new_chat_completion_common(f, *args, **kwargs):
139139
op=consts.OP.OPENAI_CHAT_COMPLETIONS_CREATE,
140140
description="Chat Completion",
141141
origin=OpenAIIntegration.origin,
142+
only_if_parent=True,
142143
)
143144
span.__enter__()
144145

@@ -324,6 +325,7 @@ def _new_embeddings_create_common(f, *args, **kwargs):
324325
op=consts.OP.OPENAI_EMBEDDINGS_CREATE,
325326
description="OpenAI Embedding Creation",
326327
origin=OpenAIIntegration.origin,
328+
only_if_parent=True,
327329
) as span:
328330
if "input" in kwargs and (
329331
should_send_default_pii() and integration.include_prompts

sentry_sdk/integrations/pymongo.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,7 @@ def started(self, event):
153153
op=OP.DB,
154154
name=query,
155155
origin=PyMongoIntegration.origin,
156+
only_if_parent=True,
156157
)
157158

158159
with capture_internal_exceptions():

sentry_sdk/integrations/ray.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@ def _remote_method_with_header_propagation(*args, **kwargs):
8888
op=OP.QUEUE_SUBMIT_RAY,
8989
name=qualname_from_function(f),
9090
origin=RayIntegration.origin,
91+
only_if_parent=True,
9192
) as span:
9293
tracing = {
9394
k: v

sentry_sdk/integrations/redis/_async_common.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ async def _sentry_execute(self, *args, **kwargs):
4040
op=OP.DB_REDIS,
4141
name="redis.pipeline.execute",
4242
origin=SPAN_ORIGIN,
43+
only_if_parent=True,
4344
) as span:
4445
with capture_internal_exceptions():
4546
span_data = get_db_data_fn(self)
@@ -84,6 +85,7 @@ async def _sentry_execute_command(self, name, *args, **kwargs):
8485
op=cache_properties["op"],
8586
name=cache_properties["description"],
8687
origin=SPAN_ORIGIN,
88+
only_if_parent=True,
8789
)
8890
cache_span.__enter__()
8991

@@ -93,6 +95,7 @@ async def _sentry_execute_command(self, name, *args, **kwargs):
9395
op=db_properties["op"],
9496
name=db_properties["description"],
9597
origin=SPAN_ORIGIN,
98+
only_if_parent=True,
9699
)
97100
db_span.__enter__()
98101

sentry_sdk/integrations/redis/_sync_common.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ def sentry_patched_execute(self, *args, **kwargs):
4141
op=OP.DB_REDIS,
4242
name="redis.pipeline.execute",
4343
origin=SPAN_ORIGIN,
44+
only_if_parent=True,
4445
) as span:
4546
with capture_internal_exceptions():
4647
span_data = get_db_data_fn(self)

sentry_sdk/integrations/socket.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ def create_connection(
5757
op=OP.SOCKET_CONNECTION,
5858
name=_get_span_description(address[0], address[1]),
5959
origin=SocketIntegration.origin,
60+
only_if_parent=True,
6061
) as span:
6162
span.set_data("address", address)
6263
span.set_data("timeout", timeout)
@@ -83,6 +84,7 @@ def getaddrinfo(host, port, family=0, type=0, proto=0, flags=0):
8384
op=OP.SOCKET_DNS,
8485
name=_get_span_description(host, port),
8586
origin=SocketIntegration.origin,
87+
only_if_parent=True,
8688
) as span:
8789
span.set_data("host", host)
8890
span.set_data("port", port)

sentry_sdk/integrations/starlette.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,7 @@ async def _create_span_call(app, scope, receive, send, **kwargs):
164164
op=OP.MIDDLEWARE_STARLETTE,
165165
name=middleware_name,
166166
origin=StarletteIntegration.origin,
167+
only_if_parent=True,
167168
) as middleware_span:
168169
middleware_span.set_tag("starlette.middleware_name", middleware_name)
169170

@@ -174,6 +175,7 @@ async def _sentry_receive(*args, **kwargs):
174175
op=OP.MIDDLEWARE_STARLETTE_RECEIVE,
175176
name=getattr(receive, "__qualname__", str(receive)),
176177
origin=StarletteIntegration.origin,
178+
only_if_parent=True,
177179
) as span:
178180
span.set_tag("starlette.middleware_name", middleware_name)
179181
return await receive(*args, **kwargs)
@@ -189,6 +191,7 @@ async def _sentry_send(*args, **kwargs):
189191
op=OP.MIDDLEWARE_STARLETTE_SEND,
190192
name=getattr(send, "__qualname__", str(send)),
191193
origin=StarletteIntegration.origin,
194+
only_if_parent=True,
192195
) as span:
193196
span.set_tag("starlette.middleware_name", middleware_name)
194197
return await send(*args, **kwargs)

0 commit comments

Comments
 (0)