Skip to content

feat(boto3): Add response, retry, and error span attributes - #7499

Open
pabloDeputter wants to merge 20 commits into
pablo/improve-boto3-call-lifecyclefrom
pablo/add-boto3-response-retry-error-attributes
Open

pabloDeputter wants to merge 20 commits into
pablo/improve-boto3-call-lifecyclefrom
pablo/add-boto3-response-retry-error-attributes

Conversation

@pabloDeputter

@pabloDeputter pabloDeputter commented Sep 14, 2026 •

Copy link
Copy Markdown
Member

Description

Add generic response, retry, and error attribute enrichment to boto3 spans. Previously, only recorded request and client metadata was instrumented; information after the call such as HTTP status, retry count, etc was omitted. The new attributes follow the OTel AWS SDK conventions.

Changes

  • add SPANDATA consts: AWS_REQUEST_ID, AWS_EXTENDED_REQUEST_ID, HTTP_REQUEST_RESEND_COUNT, and ERROR_TYPE.
  • add _get_response_attributes() to extract http.response_status_code, http.request_resend_count, aws.request_id, and aws.extended_request_id.
  • Add erorr.type from ClientError.Eror.Code or the exception class, without recording error messages.

Issues

Resolves #7476

@pabloDeputter
pabloDeputter added this pull request to stack #7500 September 14, 2026 12:53
@github-actions

github-actions Bot commented Sep 14, 2026 •

Copy link
Copy Markdown
Contributor

Codecov Results 📊

✅ 130355 passed | ⏭️ 7192 skipped | Total: 137547 | Pass Rate: 94.77% | Execution Time: 445m 57s

📊 Comparison with Base Branch

Metric Change
Total Tests 📈 +688
Passed Tests 📈 +665
Failed Tests —
Skipped Tests 📈 +23

All tests are passing successfully.

✅ Patch coverage is 100.00%. Project has 2561 uncovered lines.
✅ Project coverage is 90.32%. Comparing base (dca0a7b) to head (8a6a245).

Files with missing lines (1)
File Patch % Lines
sentry_sdk/integrations/boto3/_instrumentation.py 100.00% ⚠️ 2 partials
Coverage diff
@@            Coverage Diff             @@
##        master       #PR       +/-##
==========================================
+ Coverage    90.28%    90.32%    +0.04%
==========================================
  Files          195       199        +4
  Lines        26195     26460      +265
  Branches      9758      9824       +66
==========================================
+ Hits         23649     23899      +250
- Misses        2546      2561       +15
- Partials      1483      1493       +10

Generated by Codecov Action

@pabloDeputter pabloDeputter changed the title Pablo/add boto3 response retry error attributes feat(boto3): Add response, retry, and error span attributes Sep 14, 2026
@pabloDeputter
pabloDeputter force-pushed the pablo/add-boto3-response-retry-error-attributes branch from a15c641 to 56a7ab6 Compare September 14, 2026 14:42
@pabloDeputter
pabloDeputter force-pushed the pablo/add-boto3-response-retry-error-attributes branch from 56a7ab6 to 176096b Compare September 15, 2026 12:58
Comment thread tests/integrations/boto3/test_client.py
@pabloDeputter
pabloDeputter force-pushed the pablo/add-boto3-response-retry-error-attributes branch from af6b9a8 to 49474d0 Compare September 17, 2026 15:48
@pabloDeputter
pabloDeputter force-pushed the pablo/add-boto3-response-retry-error-attributes branch 2 times, most recently from 2e63bac to 35f0dc3 Compare September 17, 2026 16:00
@pabloDeputter
pabloDeputter marked this pull request as ready for review September 17, 2026 16:07
@pabloDeputter
pabloDeputter requested a review from a team as a code owner September 17, 2026 16:07
@pabloDeputter
pabloDeputter force-pushed the pablo/add-boto3-response-retry-error-attributes branch from 76e7425 to f922864 Compare September 18, 2026 13:02

@cursor cursor Bot left a comment •

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Stale Bugbot comment from a previous run.

Comment thread sentry_sdk/integrations/boto3/_client.py Outdated
@pabloDeputter
pabloDeputter removed this pull request from stack #7500 September 18, 2026 14:34
@pabloDeputter
pabloDeputter added this pull request to stack #7539 September 18, 2026 14:35
@pabloDeputter
pabloDeputter force-pushed the pablo/add-boto3-response-retry-error-attributes branch from 4fae1c9 to cdd5c95 Compare September 18, 2026 15:06
@pabloDeputter
pabloDeputter removed this pull request from stack #7539 September 18, 2026 15:08
@pabloDeputter
pabloDeputter added this pull request to stack #7541 September 18, 2026 15:08
@pabloDeputter
pabloDeputter force-pushed the pablo/add-boto3-response-retry-error-attributes branch from cdd5c95 to d55060f Compare September 18, 2026 15:20
@pabloDeputter
pabloDeputter force-pushed the pablo/add-boto3-response-retry-error-attributes branch 3 times, most recently from 6c9e3a8 to a72a791 Compare September 21, 2026 16:07
@pabloDeputter
pabloDeputter force-pushed the pablo/add-boto3-response-retry-error-attributes branch from 8f65118 to 96a40ea Compare September 22, 2026 14:53
@pabloDeputter
pabloDeputter removed this pull request from stack #7541 September 22, 2026 14:57
@pabloDeputter
pabloDeputter added this pull request to stack #7618 September 22, 2026 14:57
_set_span_attributes(span, _get_error_attributes(error))
raise
else:
with capture_internal_exceptions():

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because this swallows exceptions, I don't think the else block is needed here, and this can instead be moved up to under line 115.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I removed the else block, but kept it outside the inner try of orig_make_api_call() cause I think that represents the behavior better: 1. call original client 2. if it fails we add error-attributes and re-raise 3. otherwise, we add response-attributes

def _set_span_attributes(
span: "Union[Span, StreamedSpan]", attributes: "Attributes"
) -> None:
"""Will be removed in the major."""

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a little vague 😅

Are you referring to the entire function? Or are you referring to a subset of the functionality that's here?

Generally speaking, for comments like these that are indicating the removal/modification of code at a particular point in time, it's worth being specific so that we know exactly which major the code is intended to be removed by.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I left the comment to justify the set_span_attributes() helper, cause otherwise you would have multiple conditionals intertwined with the other logic. It also makes it easier to move for the next major (3.0).

The goal was to merge into main and then remove all the send_default_pii and legacy streaming stuff once again and merge into the major branch and the helper makes it a little bit easier to do that.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah ok, sounds good. 👍🏻 Thanks!

attributes: "Attributes" = {}

# botocore injects HTTP status into `ResponseMetadata` after parsing.
# https://github.com/boto/botocore/blob/develop/botocore/parsers.py#L273-L284

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here and on line 111, we should use a permalink in case the upstream repository changes the file path

attributes[SPANDATA.HTTP_STATUS_CODE] = status_code

retry_attempts = metadata.get("RetryAttempts")
# botocore represents retries as `attempts - 1`; OTel suggests "if and only if", so skip zero.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This comment isn't clear to me (specifically, the otel part). From my understanding of what this attribute (HTTP_REQUEST_RESEND_COUNT) is intended to represent, it's the number of retries, which does not include the original request. Is that correct?

If that's the case, I think the code that you've written below, from lines 113 to 119, is clear enough on its own that this extra comment is unnecessary.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yepp, correct: HTTP_REQUEST_RESEND_COUNT basically represents the number of attempts before success. I'll remove the extra comment

# https://opentelemetry.io/docs/specs/semconv/http/http-spans/#http-client-span
if (
isinstance(retry_attempts, int)
# avoid emitting `resend_count=True`.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Under what circumstances would reset_count be a boolean?

Comment on lines +121 to +123
headers = metadata.get("HTTPHeaders")
if not isinstance(headers, dict):
headers = {}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think this check is necessary because, based on the type definition that I can see here, the HTTPHeaders will always be a dictionary.

Comment on lines +163 to +165
if isinstance(error, dict):
error_code = error.get("Code")
if isinstance(error_code, str) and error_code:

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm surprised that you need to perform these isinstance checks because the types that I'm reading about these properties are indicating that the error will be a dictionary and the code will be a string.

Is the type checker telling you that these could be something different (like an Any)?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm pretty sure that I gaslit myself by the clanker to believe that this was justified 🫣 I wanted to make the instrumentation-code as defensive as possible so it won't throw any exceptions or we won't lose any attributes, but this is already guaranteed by capture_internal_exceptions(); but you're right, these are pretty useless cause this will almost never happen (same for HTTPHeaders and RetryAttempts);

There are more of these useless conditionals, so I'll double check these and remove these as well in the next PR.

exception_name = exception_type.__qualname__
exception_module = exception_type.__module__
if exception_module not in ("builtins", "__builtins__"):
return "%s.%s" % (exception_module, exception_name)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These can be updated to be f-strings

@pabloDeputter
pabloDeputter force-pushed the pablo/add-boto3-response-retry-error-attributes branch from 96a40ea to fd30806 Compare September 29, 2026 08:34

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit fd30806. Configure here.

Comment thread sentry_sdk/integrations/boto3/_instrumentation.py Outdated
Comment thread sentry_sdk/integrations/boto3/_instrumentation.py

@ericapisani ericapisani left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Awesome stuff 🚀

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat(boto3): Add generic response, retry, and error attributes

2 participants