Skip to content

Commit 28c1fae

Browse files
author
ADOT Patch workflow
committed
add app signals attribute translation
1 parent 9e39da9 commit 28c1fae

File tree

5 files changed

+512
-167
lines changed

5 files changed

+512
-167
lines changed

aws-opentelemetry-distro/src/amazon/opentelemetry/distro/_aws_metric_attribute_generator.py

Lines changed: 120 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,22 @@
88

99
from 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,
@@ -63,6 +71,13 @@
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+
)
6681
from amazon.opentelemetry.distro.regional_resource_arn_parser import RegionalResourceArnParser
6782
from amazon.opentelemetry.distro.sqs_url_parser import SqsUrlParser
6883
from opentelemetry.sdk.resources import Resource
@@ -105,6 +120,7 @@
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"
@@ -118,6 +134,19 @@
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+
677786
def _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

Comments
 (0)