Skip to content

Commit 0ea4cee

Browse files
authored
Merge branch 'master' into ivana/dont-attach-trace-id-if-not-known
2 parents 1d57663 + 9c1d475 commit 0ea4cee

2 files changed

Lines changed: 357 additions & 49 deletions

File tree

sentry_sdk/integrations/starlette.py

Lines changed: 69 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import functools
2+
import json
23
import warnings
34
import sys
45
from collections.abc import Set
@@ -20,10 +21,12 @@
2021
)
2122
from sentry_sdk.integrations.asgi import SentryAsgiMiddleware
2223
from sentry_sdk.scope import should_send_default_pii
24+
from sentry_sdk.traces import NoOpStreamedSpan, StreamedSpan
2325
from sentry_sdk.tracing import (
2426
SOURCE_FOR_STYLE,
2527
TransactionSource,
2628
)
29+
from sentry_sdk.tracing_utils import has_span_streaming_enabled
2730
from sentry_sdk.utils import (
2831
AnnotatedValue,
2932
capture_internal_exceptions,
@@ -154,7 +157,8 @@ async def _create_span_call(
154157
send: "Callable[[Dict[str, Any]], Awaitable[None]]",
155158
**kwargs: "Any",
156159
) -> None:
157-
integration = sentry_sdk.get_client().get_integration(StarletteIntegration)
160+
client = sentry_sdk.get_client()
161+
integration = client.get_integration(StarletteIntegration)
158162
if integration is None:
159163
return await old_call(app, scope, receive, send, **kwargs)
160164

@@ -171,22 +175,38 @@ async def _create_span_call(
171175
return await old_call(app, scope, receive, send, **kwargs)
172176

173177
middleware_name = app.__class__.__name__
178+
is_span_streaming_enabled = has_span_streaming_enabled(client.options)
179+
180+
def _start_middleware_span(op: str, name: str) -> "Any":
181+
if is_span_streaming_enabled:
182+
return sentry_sdk.traces.start_span(
183+
name=name,
184+
attributes={
185+
"sentry.op": op,
186+
"sentry.origin": StarletteIntegration.origin,
187+
"middleware.name": middleware_name,
188+
},
189+
)
190+
return sentry_sdk.start_span(
191+
op=op,
192+
name=name,
193+
origin=StarletteIntegration.origin,
194+
)
174195

175-
with sentry_sdk.start_span(
176-
op=OP.MIDDLEWARE_STARLETTE,
177-
name=middleware_name,
178-
origin=StarletteIntegration.origin,
196+
with _start_middleware_span(
197+
op=OP.MIDDLEWARE_STARLETTE, name=middleware_name
179198
) as middleware_span:
180-
middleware_span.set_tag("starlette.middleware_name", middleware_name)
199+
if not is_span_streaming_enabled:
200+
middleware_span.set_tag("starlette.middleware_name", middleware_name)
181201

182202
# Creating spans for the "receive" callback
183203
async def _sentry_receive(*args: "Any", **kwargs: "Any") -> "Any":
184-
with sentry_sdk.start_span(
204+
with _start_middleware_span(
185205
op=OP.MIDDLEWARE_STARLETTE_RECEIVE,
186206
name=getattr(receive, "__qualname__", str(receive)),
187-
origin=StarletteIntegration.origin,
188207
) as span:
189-
span.set_tag("starlette.middleware_name", middleware_name)
208+
if not is_span_streaming_enabled:
209+
span.set_tag("starlette.middleware_name", middleware_name)
190210
return await receive(*args, **kwargs)
191211

192212
receive_name = getattr(receive, "__name__", str(receive))
@@ -195,12 +215,12 @@ async def _sentry_receive(*args: "Any", **kwargs: "Any") -> "Any":
195215

196216
# Creating spans for the "send" callback
197217
async def _sentry_send(*args: "Any", **kwargs: "Any") -> "Any":
198-
with sentry_sdk.start_span(
218+
with _start_middleware_span(
199219
op=OP.MIDDLEWARE_STARLETTE_SEND,
200220
name=getattr(send, "__qualname__", str(send)),
201-
origin=StarletteIntegration.origin,
202221
) as span:
203-
span.set_tag("starlette.middleware_name", middleware_name)
222+
if not is_span_streaming_enabled:
223+
span.set_tag("starlette.middleware_name", middleware_name)
204224
return await send(*args, **kwargs)
205225

206226
send_name = getattr(send, "__name__", str(send))
@@ -221,6 +241,16 @@ async def _sentry_send(*args: "Any", **kwargs: "Any") -> "Any":
221241
return middleware_class
222242

223243

244+
def _serialize_body_data(data: "Any") -> str:
245+
# data may be a JSON-serializable value, an AnnotatedValue, or a dict with AnnotatedValue values
246+
def _default(value: "Any") -> "Any":
247+
if isinstance(value, AnnotatedValue):
248+
return value.value
249+
return str(value)
250+
251+
return json.dumps(data, default=_default)
252+
253+
224254
@ensure_integration_enabled(StarletteIntegration)
225255
def _capture_exception(exception: BaseException, handled: "Any" = False) -> None:
226256
event, hint = event_from_exception(
@@ -446,9 +476,8 @@ def _sentry_request_response(func: "Callable[[Any], Any]") -> "ASGIApp":
446476
if is_coroutine:
447477

448478
async def _sentry_async_func(*args: "Any", **kwargs: "Any") -> "Any":
449-
integration = sentry_sdk.get_client().get_integration(
450-
StarletteIntegration
451-
)
479+
client = sentry_sdk.get_client()
480+
integration = client.get_integration(StarletteIntegration)
452481
if integration is None:
453482
return await old_func(*args, **kwargs)
454483

@@ -488,6 +517,24 @@ def event_processor(
488517
_make_request_event_processor(request, integration)
489518
)
490519

520+
is_span_streaming_enabled = has_span_streaming_enabled(client.options)
521+
if is_span_streaming_enabled:
522+
current_span = sentry_sdk.get_current_span()
523+
524+
if (
525+
info
526+
and "data" in info
527+
and isinstance(current_span, StreamedSpan)
528+
and not isinstance(current_span, NoOpStreamedSpan)
529+
):
530+
data = info["data"]
531+
532+
with capture_internal_exceptions():
533+
current_span._segment.set_attribute(
534+
"http.request.body.data",
535+
_serialize_body_data(data),
536+
)
537+
491538
return await old_func(*args, **kwargs)
492539

493540
func = _sentry_async_func
@@ -503,7 +550,13 @@ def _sentry_sync_func(*args: "Any", **kwargs: "Any") -> "Any":
503550
return old_func(*args, **kwargs)
504551

505552
current_scope = sentry_sdk.get_current_scope()
506-
if current_scope.transaction is not None:
553+
current_span = current_scope.span
554+
555+
if isinstance(current_span, StreamedSpan) and not isinstance(
556+
current_span, NoOpStreamedSpan
557+
):
558+
current_span._segment._update_active_thread()
559+
elif current_scope.transaction is not None:
507560
current_scope.transaction.update_active_thread()
508561

509562
sentry_scope = sentry_sdk.get_isolation_scope()

0 commit comments

Comments
 (0)