1616from sentry_sdk .integrations .boto3 import Boto3Integration
1717from sentry_sdk .integrations .boto3 ._services .base import _ServiceExtension
1818from sentry_sdk .integrations .boto3 ._services .registry import _SERVICE_EXTENSIONS
19+ from sentry_sdk .integrations .boto3 ._services .s3 import _S3Extension
1920from sentry_sdk .integrations .boto3 .consts import (
2021 AWS_RPC_SYSTEM_NAME ,
2122 CLOUD_PROVIDER ,
@@ -146,7 +147,7 @@ def record_client_span(request, **kwargs):
146147 if span ["name" ] == "S3.GetObject"
147148 and (
148149 span .get ("attributes" , {}).get (SPANDATA .SENTRY_ORIGIN ) == ORIGIN
149- and span .get ("attributes" , {}).get (SPANDATA .SENTRY_OP ) == OP .RPC
150+ and span .get ("attributes" , {}).get (SPANDATA .SENTRY_OP ) == OP .OBJECT_GET
150151 )
151152 ]
152153 http_spans = [
@@ -251,7 +252,7 @@ def test_omit_url_data_if_parsing_fails(capture_items, client_factory):
251252 )
252253
253254 parse_url .assert_called ()
254- (span ,) = spans_by_op [OP .RPC ]
255+ (span ,) = spans_by_op [OP .OBJECT_HEAD ]
255256 attributes = span .get ("attributes" , {})
256257 assert SPANDATA .URL_FULL not in attributes
257258 assert SPANDATA .URL_FRAGMENT not in attributes
@@ -326,7 +327,7 @@ def test_url_query_data_collection(
326327 (span ,) = [
327328 item .payload
328329 for item in items
329- if item .payload .get ("attributes" , {}).get (SPANDATA .SENTRY_OP ) == OP .RPC
330+ if item .payload .get ("attributes" , {}).get (SPANDATA .SENTRY_OP ) == OP .OBJECT_LIST
330331 ]
331332 attributes = span .get ("attributes" , {})
332333
@@ -428,9 +429,8 @@ def _capture_stubbed_client_span(
428429 )
429430 stubber .assert_no_pending_responses ()
430431
431- client_spans = spans_by_op .get (OP .RPC , [])
432- assert len (client_spans ) == 1
433- return client_spans [0 ]
432+ ((client_span ,),) = spans_by_op .values ()
433+ return client_span
434434
435435
436436def test_service_extension_customizes_client_span (
@@ -503,6 +503,7 @@ def get_response_attributes(self, ctx, response):
503503 "method_name" ,
504504 "api_params" ,
505505 "span_name" ,
506+ "expected_op" ,
506507 "rpc_service" ,
507508 "rpc_method" ,
508509 "endpoint_url" ,
@@ -515,6 +516,7 @@ def get_response_attributes(self, ctx, response):
515516 "head_object" ,
516517 {"Bucket" : "bucket" , "Key" : "foo" },
517518 "S3.HeadObject" ,
519+ OP .OBJECT_HEAD ,
518520 "S3" ,
519521 "HeadObject" ,
520522 "http://localhost:4566" ,
@@ -526,6 +528,7 @@ def get_response_attributes(self, ctx, response):
526528 "list_event_buses" ,
527529 {},
528530 "EventBridge.ListEventBuses" ,
531+ OP .RPC ,
529532 "EventBridge" ,
530533 "ListEventBuses" ,
531534 None ,
@@ -537,6 +540,7 @@ def get_response_attributes(self, ctx, response):
537540 "get_rest_apis" ,
538541 {},
539542 "APIGateway.GetRestApis" ,
543+ OP .RPC ,
540544 "APIGateway" ,
541545 "GetRestApis" ,
542546 None ,
@@ -552,6 +556,7 @@ def test_client_call_has_common_attributes(
552556 method_name ,
553557 api_params ,
554558 span_name ,
559+ expected_op ,
555560 rpc_service ,
556561 rpc_method ,
557562 endpoint_url ,
@@ -576,7 +581,7 @@ def test_client_call_has_common_attributes(
576581
577582 assert span ["name" ] == span_name
578583 assert span .get ("end_timestamp" ) is not None
579- assert attributes [SPANDATA .SENTRY_OP ] == OP . RPC
584+ assert attributes [SPANDATA .SENTRY_OP ] == expected_op
580585 assert attributes [SPANDATA .SENTRY_ORIGIN ] == ORIGIN
581586 assert attributes [SPANDATA .SENTRY_KIND ] == "client"
582587 assert attributes [SPANDATA .CLOUD_PROVIDER ] == CLOUD_PROVIDER
@@ -647,7 +652,7 @@ def test_client_call_has_response_header_attributes(
647652 capture_items ,
648653 )
649654
650- spans = spans_by_op [OP .RPC ]
655+ spans = spans_by_op [OP .OBJECT_HEAD ]
651656 assert len (spans ) == 1
652657 attributes = spans [0 ].get ("attributes" , {})
653658 assert attributes [SPANDATA .HTTP_STATUS_CODE ] == 200
@@ -666,7 +671,7 @@ def test_retry_attempts_share_one_client_span(
666671 spans_by_op = _capture_boto3_spans_by_op (
667672 lambda : client .head_object (Bucket = "bucket" , Key = "foo" ), capture_items
668673 )
669- client_spans = spans_by_op .get (OP .RPC , [])
674+ client_spans = spans_by_op .get (OP .OBJECT_HEAD , [])
670675
671676 assert len (request_span_ids ) == attempt_count
672677 # all `AWSRequest` instances created during retries reference the same client span.
@@ -689,7 +694,7 @@ def attempt_failed_head_object_call():
689694 spans_by_op = _capture_boto3_spans_by_op (
690695 attempt_failed_head_object_call , capture_items
691696 )
692- client_spans = spans_by_op .get (OP .RPC , [])
697+ client_spans = spans_by_op .get (OP .OBJECT_HEAD , [])
693698
694699 assert len (request_span_ids ) == 2
695700 assert len (set (request_span_ids )) == 1
@@ -706,7 +711,7 @@ def test_client_error_has_response_attributes_and_is_unchanged(
706711 monkeypatch ,
707712 with_service_extension ,
708713):
709- class TestServiceExtension (_ServiceExtension ):
714+ class TestServiceExtension (_S3Extension ):
710715 def get_response_attributes (self , ctx , response ):
711716 return {
712717 "aws.test.error" : response ["Error" ]["Code" ],
@@ -745,14 +750,14 @@ def invoke_failing_client_method():
745750 spans_by_op = _capture_boto3_spans_by_op (
746751 invoke_failing_client_method , capture_items
747752 )
748- client_spans = spans_by_op .get (OP .RPC , [])
753+ client_spans = spans_by_op .get (OP .OBJECT_HEAD , [])
749754 _assert_one_failed_span (client_spans )
750755 attributes = client_spans [0 ].get ("attributes" , {})
751756
752757 span = client_spans [0 ]
753758 assert span ["name" ] == "S3.HeadObject"
754759 assert span .get ("end_timestamp" ) is not None
755- assert attributes [SPANDATA .SENTRY_OP ] == OP .RPC
760+ assert attributes [SPANDATA .SENTRY_OP ] == OP .OBJECT_HEAD
756761 assert attributes [SPANDATA .SENTRY_ORIGIN ] == ORIGIN
757762 assert attributes [SPANDATA .SENTRY_KIND ] == "client"
758763 assert attributes [SPANDATA .CLOUD_PROVIDER ] == CLOUD_PROVIDER
@@ -806,7 +811,7 @@ def invoke_failing_client_method():
806811 spans_by_op = _capture_boto3_spans_by_op (
807812 invoke_failing_client_method , capture_items
808813 )
809- client_spans = spans_by_op .get (OP .RPC , [])
814+ client_spans = spans_by_op .get (OP .OBJECT_HEAD , [])
810815 _assert_one_failed_span (client_spans )
811816
812817 expected_error_type = (
@@ -852,7 +857,7 @@ def invoke_client_method():
852857 stubber .add_response ("head_object" , original_response , api_params )
853858 spans_by_op = _capture_boto3_spans_by_op (invoke_client_method , capture_items )
854859
855- client_spans = spans_by_op .get (OP .RPC , [])
860+ client_spans = spans_by_op .get (OP .OBJECT_HEAD , [])
856861 assert returned_responses == [original_response ]
857862 assert returned_responses [0 ] is original_response
858863 if failing_instrumentation == "_get_response_attributes" :
@@ -889,7 +894,7 @@ def invoke_failing_client_method():
889894 spans_by_op = _capture_boto3_spans_by_op (
890895 invoke_failing_client_method , capture_items
891896 )
892- client_spans = spans_by_op .get (OP .RPC , [])
897+ client_spans = spans_by_op .get (OP .OBJECT_HEAD , [])
893898
894899 assert len (client_spans ) == 1
895900 assert client_spans [0 ]["status" ] == "error"
@@ -922,7 +927,7 @@ def invoke_client_method_and_read_body():
922927 spans_by_op = _capture_boto3_spans_by_op (
923928 invoke_client_method_and_read_body , capture_items
924929 )
925- client_spans = spans_by_op .get (OP .RPC , [])
930+ client_spans = spans_by_op .get (OP .OBJECT_GET , [])
926931 stream_spans = spans_by_op .get (OP .HTTP_CLIENT_STREAM , [])
927932
928933 assert len (client_spans ) == 1
@@ -971,7 +976,7 @@ def invoke_client_method_and_read_body():
971976 spans_by_op = _capture_boto3_spans_by_op (
972977 invoke_client_method_and_read_body , capture_items
973978 )
974- client_spans = spans_by_op .get (OP .RPC , [])
979+ client_spans = spans_by_op .get (OP .OBJECT_GET , [])
975980 stream_spans = spans_by_op .get (OP .HTTP_CLIENT_STREAM , [])
976981
977982 assert len (client_spans ) == 1
0 commit comments