Skip to content

Commit a4cb500

Browse files
committed
add some more comments
1 parent eecb7fb commit a4cb500

2 files changed

Lines changed: 19 additions & 8 deletions

File tree

‎sentry_sdk/integrations/boto3/_client.py‎

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,19 @@
2929
def _activate_client_span(
3030
span: "Union[Span, StreamedSpan]",
3131
) -> "Iterator[Union[Span, StreamedSpan]]":
32-
"""Temporarily activate an inactive boto span without ending it."""
32+
"""
33+
Activate the boto span temporarily during `_make_api_call()` without ending it.
34+
35+
Botocore returns a `StreamingBody` before its bytes are consumed. Using the
36+
context manager would finish it as soon as `_make_api_call()` returns, so
37+
restore the caller's span here and let the `StreamingBody` wrapper finish
38+
the boto span when body is consumed/closed.
39+
40+
faulty: desired:
41+
boto3 [_make_api_call] boto3 [_make_api_call------]
42+
http [request] http [request]
43+
stream [read] stream [read]
44+
"""
3345
if isinstance(span, NoOpStreamedSpan):
3446
yield span
3547
return

‎sentry_sdk/integrations/boto3/_instrumentation.py‎

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -105,12 +105,11 @@ def _instrument_streaming_body(
105105
if isinstance(span, StreamedSpan):
106106
streaming_span = sentry_sdk.traces.start_span(
107107
name=span.name,
108-
# `parent_span` is set explicitly to the boto span.
108+
# keep stream span under the boto span after `_make_api_call()` returns.
109109
parent_span=span,
110-
# avoid making the streaming span the current span on the scope since the application might
111-
# keep `StreamingBody` open before reading it. Otherwise: 1. when the streamingspan ends it
112-
# could restore the parent span on the scope, breaking the parent-child relation of newly
113-
# created spans; 2. newly created spans would be attached to the streaming span.
110+
# the body may outlive the api call, so keep it inactive. Otherwise it
111+
# 1. could restore the already-finished boto span when it ends; 2. make
112+
# unrelated new spans attach to the stream span since it's the current span.
114113
active=False,
115114
attributes={
116115
"sentry.op": OP.HTTP_CLIENT_STREAM,
@@ -133,6 +132,7 @@ def finish_span(error: "Optional[BaseException]" = None) -> None:
133132
return
134133

135134
finished = True
135+
# finish stream span before boto span, and only once across read/close.
136136
_finish_span(streaming_span, error)
137137
_finish_span(span, error)
138138

@@ -152,6 +152,7 @@ def sentry_streaming_body_read(*args: "Any", **kwargs: "Any") -> bytes:
152152
read_return_value = orig_read(*args, **kwargs)
153153
with capture_internal_exceptions():
154154
amount_of_bytes_requested = args[0] if args else kwargs.get("amt")
155+
# detect read-to-end, eof, or the known content length being consumed.
155156
if (
156157
amount_of_bytes_requested is None
157158
or amount_of_bytes_requested < 0
@@ -189,8 +190,6 @@ def sentry_raw_stream_close(*args: "Any", **kwargs: "Any") -> None:
189190
raw_stream = body._raw_stream # type: ignore[attr-defined]
190191
orig_raw_close = raw_stream.close
191192

192-
# StreamingBody.__exit__ closes `_raw_stream` directly, bypassing
193-
# StreamingBody.close(), so both levels need to be instrumented.
194193
raw_stream.close = sentry_raw_stream_close
195194
body.read = sentry_streaming_body_read # type: ignore
196195
body.close = sentry_streaming_body_close # type: ignore

0 commit comments

Comments
 (0)