feat(boto3): Add S3 service extension - #7617
pabloDeputter wants to merge 72 commits into
Conversation
d8279cc to
d7727cd
Compare
ca45d46 to
0c2873f
Compare
Codecov Results 📊✅ 132785 passed | ❌ 1 failed | ⏭️ 7220 skipped | Total: 140006 | Pass Rate: 94.84% | Execution Time: 452m 28s 📊 Comparison with Base Branch
➕ New Tests (1)View new tests
❌ Failed Tests
|
| File | Patch % | Lines |
|---|---|---|
| sentry_sdk/integrations/boto3/_services/s3.py | 72.09% | |
| sentry_sdk/integrations/boto3/_services/_attribute_extraction.py | 93.75% |
Coverage diff
@@ Coverage Diff @@
## master #PR +/-##
==========================================
+ Coverage 90.29% 90.35% +0.06%
==========================================
Files 195 204 +9
Lines 26252 26625 +373
Branches 9792 9882 +90
==========================================
+ Hits 23703 24056 +353
- Misses 2549 2569 +20
- Partials 1486 1493 +7Generated by Codecov Action
d7727cd to
c1249cb
Compare
0c2873f to
70218f1
Compare
| return {} | ||
|
|
||
| attributes = {} | ||
| for param, attribute, convert in specs: |
There was a problem hiding this comment.
PutObject object size is read from an absent response field
PutObject responses do not include Size, so this mapping leaves aws.s3.object_size unset. Extract ContentLength from the request params for PutObject, as the PR description specifies.
Evidence
_RESPONSE_OBJECT_SIZE_FIELDSmapsPutObjecttoSize.get_response_attributes()reads that field from the response and only setsaws.s3.object_sizewhen it is an integer.- The S3
PutObjectresponse has noSize; request extraction does not otherwise captureContentLength.
Also found at 2 additional locations
sentry_sdk/integrations/boto3/_services/registry.py:15-15sentry_sdk/integrations/boto3/_services/s3.py:28-31
Identified by Warden · code-review, find-bugs · F8T-EAX
| _SERVICE_EXTENSIONS: "Dict[str, Tuple[str, str]]" = { | ||
| "s3": ("sentry_sdk.integrations.boto3._services.s3", "_S3Extension"), | ||
| } |
There was a problem hiding this comment.
S3 attribute extraction is not covered by tests
Please add tests that assert the new S3 request and response attributes, including the operation-specific object-size and response-body-size behavior. The existing S3 tests do not verify these fields, so regressions in the new extraction logic could go undetected.
Evidence
_S3Extension.get_request_attributesextracts S3 request fields and handlesCompleteMultipartUploadobject size._S3Extension.get_response_attributeshas operation-specific logic for response body size and object size, including rangedHeadObjectcalls.- The boto3 tests do not assert
SPANDATA.AWS_S3_*orHTTP_RESPONSE_BODY_SIZE; existingApproxDictassertions allow additional attributes without checking them.
Also found at 1 additional location
sentry_sdk/integrations/boto3/_services/s3.py:64-109
Identified by Warden · code-review · VBM-G26
| # the appropriate type. | ||
| # https://opentelemetry.io/docs/specs/semconv/object-stores/s3/ | ||
| ("Bucket", SPANDATA.AWS_S3_BUCKET, _as_string), | ||
| ("CopySource", SPANDATA.AWS_S3_COPY_SOURCE, _as_string), |
There was a problem hiding this comment.
CopySource dict form silently drops aws.s3.copy_source
Boto3 often passes CopySource as a dict (Bucket/Key/VersionId); _as_string rejects that and omits aws.s3.copy_source—normalize dicts to the bucket/key string form.
Evidence
_REQUEST_ATTRIBUTESconvertsCopySourcewith_as_string._as_stringonly accepts non-emptystrvalues and returnsNonefor dicts.- Boto3 documents
CopySourceasstr or dict; dict form is common forcopy_object/copy_from, so the attribute is dropped on a frequent path.
Also found at 1 additional location
sentry_sdk/integrations/boto3/_services/registry.py:15-15
Identified by Warden · code-review, find-bugs · 8LX-QYJ
|
|
||
| if operation_name in _RESPONSE_BODY_SIZE_OPERATIONS: | ||
| # `ContentLength` is the size of the HTTP body returned, which may be a range. | ||
| content_length = _as_integer(response.get("ContentLength")) | ||
| if content_length is not None and content_length >= 0: | ||
| attributes[SPANDATA.HTTP_RESPONSE_BODY_SIZE] = content_length | ||
|
|
||
| # these fields report the total S3 object size, not the HTTP body size. | ||
| object_size_field = _RESPONSE_OBJECT_SIZE_FIELDS.get(operation_name) | ||
| if object_size_field is not None: | ||
| object_size = _as_integer(response.get(object_size_field)) | ||
| if object_size is not None and object_size >= 0: | ||
| attributes[SPANDATA.AWS_S3_OBJECT_SIZE] = object_size | ||
|
|
||
| if ( | ||
| operation_name == "HeadObject" | ||
| and "Range" not in ctx.params | ||
| and "PartNumber" not in ctx.params | ||
| ): | ||
| # an un-ranged `HEAD` has no body, so `ContentLength` is the object size. | ||
| object_size = _as_integer(response.get("ContentLength")) | ||
| if object_size is not None and object_size >= 0: | ||
| attributes[SPANDATA.AWS_S3_OBJECT_SIZE] = object_size |
There was a problem hiding this comment.
Non-ranged GetObject never sets aws.s3.object_size
Un-ranged GetObject only sets http.response.body.size from ContentLength; mirror the HeadObject guard so full-object gets also set aws.s3.object_size.
Evidence
- For
GetObject,ContentLengthis only written toSPANDATA.HTTP_RESPONSE_BODY_SIZE. aws.s3.object_sizefromContentLengthis set only for un-rangedHeadObject(Range/PartNumberabsent).GetObjectis not in_RESPONSE_OBJECT_SIZE_FIELDSand has no equivalent un-ranged branch.- PR intent: object size from
ContentLengthonGetObjectandHeadObjectresponses when not a range.
Identified by Warden · find-bugs · 6BP-LMY
There was a problem hiding this comment.
Fix attempt detected (commit 85a8895)
The S3 response-attribute code adds an un-ranged HeadObject object-size branch, but still only records ContentLength for GetObject as the HTTP body size, so the reported issue persists.
The original issue appears unresolved. Please review and try again.
Evaluated by Warden
5c6b2b0 to
5e335b5
Compare
2fdaa4b to
85a8895
Compare
5e335b5 to
70414fe
Compare
85a8895 to
a0c0e25
Compare
70414fe to
0a53853
Compare
- otherwise service-specific spans with different origins would be skipped (e.g. DynamoDB)
ref(boto3): improve docstring for `get_request_attributes()` Co-authored-by: Erica Pisani <hey@ericapisani.dev>
…t_span_origin()`
a0c0e25 to
7c39a6c
Compare
226f56a to
4d0bd32
Compare
Description
aws.s3.bucketrequired in almost all s3 operations exceptlist-buckets.http.response.body.sizewhich is the number of bytes in the payload.aws.s3.copy_sourceaws.s3.deleteaws.s3.keyaws.s3.part_numberaws.s3.upload_idaws.s3.object_size(not in OTel) which is the total size of the s3 object itself.ContentLengthonGetObjectandHeadObjectresponses;ObjectSizeonGetObjectAttributes, andContentLengthonPutObjectrequests. For rangedGetObjectorHeadObjectcalls,ContentLengthis the used size.Issues
Resolves #7576