Skip to content

Commit c622458

Browse files
committed
add some more comments
1 parent eeb0185 commit c622458

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
@@ -106,12 +106,11 @@ def _instrument_streaming_body(
106106
if isinstance(span, StreamedSpan):
107107
streaming_span = sentry_sdk.traces.start_span(
108108
name=span.name,
109-
# `parent_span` is set explicitly to the boto span.
109+
# keep stream span under the boto span after `_make_api_call()` returns.
110110
parent_span=span,
111-
# avoid making the streaming span the current span on the scope since the application might
112-
# keep `StreamingBody` open before reading it. Otherwise: 1. when the streamingspan ends it
113-
# could restore the parent span on the scope, breaking the parent-child relation of newly
114-
# created spans; 2. newly created spans would be attached to the streaming span.
111+
# the body may outlive the api call, so keep it inactive. Otherwise it
112+
# 1. could restore the already-finished boto span when it ends; 2. make
113+
# unrelated new spans attach to the stream span since it's the current span.
115114
active=False,
116115
attributes={
117116
"sentry.op": OP.HTTP_CLIENT_STREAM,
@@ -134,6 +133,7 @@ def finish_span(error: "Optional[BaseException]" = None) -> None:
134133
return
135134

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

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

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

0 commit comments

Comments
 (0)