88
99from amazon .opentelemetry .distro ._aws_attribute_keys import (
1010 AWS_AUTH_ACCESS_KEY ,
11+ AWS_AUTH_CREDENTIAL_PROVIDER_ARN ,
1112 AWS_AUTH_REGION ,
1213 AWS_BEDROCK_AGENT_ID ,
14+ AWS_BEDROCK_AGENTCORE_BROWSER_ARN ,
15+ AWS_BEDROCK_AGENTCORE_CODE_INTERPRETER_ARN ,
16+ AWS_BEDROCK_AGENTCORE_GATEWAY_ARN ,
17+ AWS_BEDROCK_AGENTCORE_MEMORY_ARN ,
18+ AWS_BEDROCK_AGENTCORE_RUNTIME_ARN ,
19+ AWS_BEDROCK_AGENTCORE_RUNTIME_ENDPOINT_ARN ,
1320 AWS_BEDROCK_DATA_SOURCE_ID ,
1421 AWS_BEDROCK_GUARDRAIL_ARN ,
1522 AWS_BEDROCK_GUARDRAIL_ID ,
1623 AWS_BEDROCK_KNOWLEDGE_BASE_ID ,
1724 AWS_CLOUDFORMATION_PRIMARY_IDENTIFIER ,
1825 AWS_DYNAMODB_TABLE_ARN ,
26+ AWS_GATEWAY_TARGET_ID ,
1927 AWS_KINESIS_STREAM_ARN ,
2028 AWS_KINESIS_STREAM_NAME ,
2129 AWS_LAMBDA_FUNCTION_ARN ,
6371 SERVICE_METRIC ,
6472 MetricAttributeGenerator ,
6573)
74+ from amazon .opentelemetry .distro .patches ._bedrock_agentcore_patches import (
75+ GEN_AI_BROWSER_ID ,
76+ GEN_AI_CODE_INTERPRETER_ID ,
77+ GEN_AI_GATEWAY_ID ,
78+ GEN_AI_MEMORY_ID ,
79+ GEN_AI_RUNTIME_ID ,
80+ )
6681from amazon .opentelemetry .distro .regional_resource_arn_parser import RegionalResourceArnParser
6782from amazon .opentelemetry .distro .sqs_url_parser import SqsUrlParser
6883from opentelemetry .sdk .resources import Resource
105120_NORMALIZED_SQS_SERVICE_NAME : str = "AWS::SQS"
106121_NORMALIZED_BEDROCK_SERVICE_NAME : str = "AWS::Bedrock"
107122_NORMALIZED_BEDROCK_RUNTIME_SERVICE_NAME : str = "AWS::BedrockRuntime"
123+ _NORMALIZED_BEDROCK_AGENTCORE_SERVICE_NAME : str = "AWS::BedrockAgentCore"
108124_NORMALIZED_SECRETSMANAGER_SERVICE_NAME : str = "AWS::SecretsManager"
109125_NORMALIZED_SNS_SERVICE_NAME : str = "AWS::SNS"
110126_NORMALIZED_STEPFUNCTIONS_SERVICE_NAME : str = "AWS::StepFunctions"
118134# Special DEPENDENCY attribute value if GRAPHQL_OPERATION_TYPE attribute key is present.
119135_GRAPHQL : str = "graphql"
120136
137+ # AWS SDK service mapping for normalization
138+ _AWS_SDK_SERVICE_MAPPING = {
139+ "Bedrock Agent" : _NORMALIZED_BEDROCK_SERVICE_NAME ,
140+ "Bedrock Agent Runtime" : _NORMALIZED_BEDROCK_SERVICE_NAME ,
141+ "Bedrock Runtime" : _NORMALIZED_BEDROCK_RUNTIME_SERVICE_NAME ,
142+ "Bedrock AgentCore Control" : _NORMALIZED_BEDROCK_AGENTCORE_SERVICE_NAME ,
143+ "Bedrock AgentCore" : _NORMALIZED_BEDROCK_AGENTCORE_SERVICE_NAME ,
144+ "Secrets Manager" : _NORMALIZED_SECRETSMANAGER_SERVICE_NAME ,
145+ "SNS" : _NORMALIZED_SNS_SERVICE_NAME ,
146+ "SFN" : _NORMALIZED_STEPFUNCTIONS_SERVICE_NAME ,
147+ "Lambda" : _NORMALIZED_LAMBDA_SERVICE_NAME ,
148+ }
149+
121150_logger : Logger = getLogger (__name__ )
122151
123152
@@ -327,16 +356,6 @@ def _normalize_remote_service_name(span: ReadableSpan, service_name: str) -> str
327356 as the associated remote resource (Model) is not listed in Cloud Control.
328357 """
329358 if is_aws_sdk_span (span ):
330- aws_sdk_service_mapping = {
331- "Bedrock Agent" : _NORMALIZED_BEDROCK_SERVICE_NAME ,
332- "Bedrock Agent Runtime" : _NORMALIZED_BEDROCK_SERVICE_NAME ,
333- "Bedrock Runtime" : _NORMALIZED_BEDROCK_RUNTIME_SERVICE_NAME ,
334- "Secrets Manager" : _NORMALIZED_SECRETSMANAGER_SERVICE_NAME ,
335- "SNS" : _NORMALIZED_SNS_SERVICE_NAME ,
336- "SFN" : _NORMALIZED_STEPFUNCTIONS_SERVICE_NAME ,
337- "Lambda" : _NORMALIZED_LAMBDA_SERVICE_NAME ,
338- }
339-
340359 # Special handling for Lambda invoke operations
341360 if _is_lambda_invoke_operation (span ):
342361 lambda_function_name = span .attributes .get (AWS_LAMBDA_FUNCTION_NAME )
@@ -345,7 +364,7 @@ def _normalize_remote_service_name(span: ReadableSpan, service_name: str) -> str
345364 # is missing rather than falling back to a generic service name
346365 return lambda_function_name if lambda_function_name else UNKNOWN_REMOTE_SERVICE
347366
348- return aws_sdk_service_mapping .get (service_name , "AWS::" + service_name )
367+ return _AWS_SDK_SERVICE_MAPPING .get (service_name , "AWS::" + service_name )
349368 return service_name
350369
351370
@@ -466,6 +485,13 @@ def _set_remote_type_and_identifier(span: ReadableSpan, attributes: BoundedAttri
466485 elif is_key_present (span , GEN_AI_REQUEST_MODEL ):
467486 remote_resource_type = _NORMALIZED_BEDROCK_SERVICE_NAME + "::Model"
468487 remote_resource_identifier = _escape_delimiters (span .attributes .get (GEN_AI_REQUEST_MODEL ))
488+ elif (
489+ _AWS_SDK_SERVICE_MAPPING .get (str (span .attributes .get (_RPC_SERVICE )))
490+ == _NORMALIZED_BEDROCK_AGENTCORE_SERVICE_NAME
491+ ):
492+ agentcore_type , agentcore_identifier = _get_agentcore_resource_type_and_identifier (span )
493+ remote_resource_type = agentcore_type
494+ remote_resource_identifier = _escape_delimiters (agentcore_identifier ) if agentcore_identifier else None
469495 elif is_key_present (span , AWS_SECRETSMANAGER_SECRET_ARN ):
470496 remote_resource_type = _NORMALIZED_SECRETSMANAGER_SERVICE_NAME + "::Secret"
471497 remote_resource_identifier = _escape_delimiters (
@@ -674,6 +700,89 @@ def _set_span_kind_for_dependency(span: ReadableSpan, attributes: BoundedAttribu
674700 attributes [AWS_SPAN_KIND ] = span_kind
675701
676702
703+ def _get_agentcore_resource_type_and_identifier (span : ReadableSpan ) -> tuple [Optional [str ], Optional [str ]]:
704+ """Get BedrockAgentCore resource type and identifier based on span attributes."""
705+
706+ attrs = span .attributes
707+
708+ # This check is not necessary but added to satisfy the linter.
709+ if not attrs :
710+ return None , None
711+
712+ def extract_id_from_arn (arn : str ) -> Optional [str ]:
713+ if not arn :
714+ return None
715+ parts = arn .split ("/" )
716+ return parts [- 1 ] if parts else None
717+
718+ resource_type = None
719+ resource_identifier = None
720+
721+ # Browser
722+ browser_id = attrs .get (GEN_AI_BROWSER_ID )
723+ browser_arn = attrs .get (AWS_BEDROCK_AGENTCORE_BROWSER_ARN )
724+ if browser_id or browser_arn :
725+ id_value = browser_id or extract_id_from_arn (str (browser_arn ) if browser_arn else "" )
726+ resource_type = "Browser" if id_value == "aws.browser.v1" else "BrowserCustom"
727+ resource_identifier = str (id_value ) if id_value else None
728+
729+ # Gateway
730+ gateway_id = attrs .get (GEN_AI_GATEWAY_ID )
731+ gateway_arn = attrs .get (AWS_BEDROCK_AGENTCORE_GATEWAY_ARN )
732+ if gateway_id or gateway_arn :
733+ gateway_target_id = attrs .get (AWS_GATEWAY_TARGET_ID )
734+ if gateway_target_id :
735+ resource_type = "GatewayTarget"
736+ resource_identifier = str (gateway_target_id )
737+ else :
738+ resource_type = "Gateway"
739+ resource_identifier = (
740+ str (gateway_id ) if gateway_id else extract_id_from_arn (str (gateway_arn ) if gateway_arn else "" )
741+ )
742+
743+ # Runtime
744+ runtime_id = attrs .get (GEN_AI_RUNTIME_ID )
745+ runtime_arn = attrs .get (AWS_BEDROCK_AGENTCORE_RUNTIME_ARN )
746+ runtime_endpoint_arn = attrs .get (AWS_BEDROCK_AGENTCORE_RUNTIME_ENDPOINT_ARN )
747+ if runtime_id or runtime_arn :
748+ if runtime_endpoint_arn :
749+ resource_type = "RuntimeEndpoint"
750+ resource_identifier = str (runtime_endpoint_arn )
751+ else :
752+ resource_type = "Runtime"
753+ resource_identifier = (
754+ str (runtime_id ) if runtime_id else extract_id_from_arn (str (runtime_arn ) if runtime_arn else "" )
755+ )
756+
757+ # Code interpreter
758+ code_interpreter_id = attrs .get (GEN_AI_CODE_INTERPRETER_ID )
759+ code_interpreter_arn = attrs .get (AWS_BEDROCK_AGENTCORE_CODE_INTERPRETER_ARN )
760+ if code_interpreter_id or code_interpreter_arn :
761+ id_value = code_interpreter_id or extract_id_from_arn (str (code_interpreter_arn ) if code_interpreter_arn else "" )
762+ resource_type = "CodeInterpreter" if id_value == "aws.codeinterpreter.v1" else "CodeInterpreterCustom"
763+ resource_identifier = str (id_value ) if id_value else None
764+
765+ # Identity
766+ credential_arn = attrs .get (AWS_AUTH_CREDENTIAL_PROVIDER_ARN )
767+ if credential_arn :
768+ credential_arn_str = str (credential_arn )
769+ if "apikeycredentialprovider" in credential_arn_str :
770+ resource_type = "APIKeyCredentialProvider"
771+ if "oauth2credentialprovider" in credential_arn_str :
772+ resource_type = "OAuth2CredentialProvider"
773+ resource_identifier = extract_id_from_arn (credential_arn_str )
774+
775+ # Memory
776+ memory_id = attrs .get (GEN_AI_MEMORY_ID )
777+ memory_arn = attrs .get (AWS_BEDROCK_AGENTCORE_MEMORY_ARN )
778+ if memory_id or memory_arn :
779+ resource_type = "Memory"
780+ resource_identifier = str (memory_arn ) if memory_arn else None
781+
782+ full_resource_type = f"{ _NORMALIZED_BEDROCK_AGENTCORE_SERVICE_NAME } ::{ resource_type } " if resource_type else None
783+ return full_resource_type , resource_identifier
784+
785+
677786def _log_unknown_attribute (attribute_key : str , span : ReadableSpan ) -> None :
678787 message : str = "No valid %s value found for %s span %s"
679788 if _logger .isEnabledFor (DEBUG ):
0 commit comments