Skip to content

Commit 8b54fa7

Browse files
liustveADOT Patch workflow
andauthored
feat: Add Resource and CFN Attributes for Bedrock AgentCore spans (#495)
*Description of changes:* Follow up to: #490 1. Normalizes `AWS::Bedrock AgentCore` and `AWS::Bedrock AgentCore Control` from botocore instrumentation to `AWS::BedrockAgentCore` 2. Add Resource and CFN attributes for Bedrock AgentCore support as following: a. **Runtime**: Extract `agentRuntimeId` or parse from `agentRuntimeArn` and add into `aws.remote.resource.identifier` span attribute. Set `aws.remote.resource.type` to `AWS::BedrockAgentCore::Runtime`. b. **Runtime Endpoint**: Extract endpoint ID from `agentRuntimeEndpointArn` and add into `aws.remote.resource.identifier` span attribute, but use full ARN as `aws.cloudformation.primary.identifier`. Set `aws.remote.resource.type` to `AWS::BedrockAgentCore::RuntimeEndpoint`. c. **Browser**: Extract `browserIdentifier` or parse from `browserArn`, and add into `aws.remote.resource.identifier` span attribute. Set `aws.remote.resource.type` to `AWS::BedrockAgentCore::Browser` (for `aws.browser.v1`) or `AWS::BedrockAgentCore::BrowserCustom` (for custom browsers). d. **Gateway**: Extract `gatewayId` or parse from `gatewayArn`, and add into `aws.remote.resource.identifier` span attribute. Set `aws.remote.resource.type` to `AWS::BedrockAgentCore::Gateway`. e. **Gateway Target**: Extract `targetId` from span attributes and add into `aws.remote.resource.identifier` span attribute. Set `aws.remote.resource.type` to `AWS::BedrockAgentCore::GatewayTarget`. Takes priority over Gateway when present. f. **Code Interpreter**: Extract `codeInterpreterIdentifier` or parse from `codeInterpreterArn`, and add into `aws.remote.resource.identifier` span attribute. Set `aws.remote.resource.type` to `AWS::BedrockAgentCore::CodeInterpreter` (for `aws.codeinterpreter.v1`) or `AWS::BedrockAgentCore::CodeInterpreterCustom` (for custom interpreters). g. **Memory**: Extract `memoryId` or parse from `memoryArn` and add into `aws.remote.resource.identifier` span attribute, but use full ARN as `aws.cloudformation.primary.identifier` when available. Set `aws.remote.resource.type` to `AWS::BedrockAgentCore::Memory`. h. **Identity**: Extract provider ID from credential provider ARNs for OAuth2 and API Key credential providers and add into `aws.remote.resource.identifier` span attribute. Set `aws.remote.resource.type` to `AWS::BedrockAgentCore::OAuth2CredentialProvider` or `AWS::BedrockAgentCore::APIKeyCredentialProvider`. **Testing** 1. Contract tests added to validate E2E behavior of new Application Signals attributes. 2. Unit tests added to validate logic flow is as expected. 3. Manual testing to verify the new spans: ``` { "name": "Bedrock AgentCore.InvokeAgentRuntime", "context": { "trace_id": "0x68f7e9d8113e41fe74ca4bedf2aee364", "span_id": "0xff15834f0aa966ea", "trace_state": "[]" }, "kind": "SpanKind.CLIENT", "parent_id": null, "start_time": "2025-10-21T20:15:20.875227Z", "end_time": "2025-10-21T20:15:21.827053Z", "status": { "status_code": "UNSET" }, "attributes": { "rpc.system": "aws-api", "rpc.service": "Bedrock AgentCore", "rpc.method": "InvokeAgentRuntime", "aws.region": "us-west-2", "server.address": "bedrock-agentcore.us-west-2.amazonaws.com", "server.port": 443, "aws.auth.region": "us-west-2", "aws.auth.account.access_key": "", "aws.bedrock.agentcore.runtime.arn": "arn:aws:bedrock-agentcore:us-west-2:571600841604:runtime/app-B7cysl8fTW", "aws.local.operation": "InternalOperation", "aws.local.service": "test-genesis", "aws.remote.service": "AWS::BedrockAgentCore", "aws.remote.operation": "InvokeAgentRuntime", "aws.remote.resource.type": "AWS::BedrockAgentCore::Runtime", "aws.remote.resource.identifier": "app-B7cysl8fTW", "aws.remote.resource.cfn.primary.identifier": "app-B7cysl8fTW", "aws.remote.resource.account.access_key": "ASIAYKFQQVOCK7JJYIFI", "aws.remote.resource.region": "us-west-2", "aws.span.kind": "LOCAL_ROOT" }, "events": [], "links": [], "resource": { "attributes": { "telemetry.sdk.language": "python", "telemetry.sdk.name": "opentelemetry", "telemetry.sdk.version": "1.33.1", "service.name": "test-genesis", "telemetry.auto.version": "0.12.1.dev0-aws", "aws.local.service": "test-genesis" }, "schema_url": "" } } ``` ``` { "name": "Bedrock AgentCore.CreateEvent", "context": { "trace_id": "0x68f811f6b5b57a276e378106ac9f7bca", "span_id": "0xc60262df93b1c44f", "trace_state": "[]" }, "kind": "SpanKind.CLIENT", "parent_id": "0x98a57a740465b917", "start_time": "2025-10-21T23:06:36.435203Z", "end_time": "2025-10-21T23:06:37.069681Z", "status": { "status_code": "UNSET" }, "attributes": { "rpc.system": "aws-api", "rpc.service": "Bedrock AgentCore", "rpc.method": "CreateEvent", "aws.region": "us-west-2", "server.address": "bedrock-agentcore.us-west-2.amazonaws.com", "server.port": 443, "aws.auth.region": "us-west-2", "aws.auth.account.access_key": "", "gen_ai.memory.id": "app_mem-ZPNcI839KD", "aws.local.operation": "POST /invocations", "aws.request_id": "0eabdad1-6ab4-4efb-98c5-ef1b9bbe028a", "retry_attempts": 1, "http.status_code": 201, "aws.local.service": "test-genesis", "aws.remote.service": "AWS::BedrockAgentCore", "aws.remote.operation": "CreateEvent", "aws.remote.resource.type": "AWS::BedrockAgentCore::Memory", "aws.remote.resource.identifier": "app_mem-ZPNcI839KD", "aws.remote.resource.cfn.primary.identifier": "app_mem-ZPNcI839KD", "aws.remote.resource.account.access_key": "", "aws.remote.resource.region": "us-west-2", "aws.span.kind": "CLIENT" }, "events": [], "links": [], "resource": { "attributes": { "telemetry.sdk.language": "python", "telemetry.sdk.name": "opentelemetry", "telemetry.sdk.version": "1.33.1", "service.name": "test-genesis", "telemetry.auto.version": "0.12.1.dev0-aws", "aws.local.service": "test-genesis" }, "schema_url": "" } } ``` By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice. --------- Co-authored-by: ADOT Patch workflow <[email protected]>
1 parent bf43ed0 commit 8b54fa7

File tree

9 files changed

+1252
-209
lines changed

9 files changed

+1252
-209
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ For any change that affects end users of this package, please add an entry under
1111
If your change does not need a CHANGELOG entry, add the "skip changelog" label to your PR.
1212

1313
## Unreleased
14+
- Add Resource and CFN Attributes for Bedrock AgentCore spans
15+
([#495](https://github.com/aws-observability/aws-otel-python-instrumentation/pull/495))
1416
- Add botocore instrumentation extension for Bedrock AgentCore services with span attributes
1517
([#490](https://github.com/aws-observability/aws-otel-python-instrumentation/pull/490))
1618
- [PATCH] Only decode JSON input buffer in Anthropic Claude streaming

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

Lines changed: 235 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.semconv._incubating.attributes.gen_ai_attributes 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,16 @@ 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, agentcore_cfn_id = (
493+
_get_bedrock_agentcore_resource_type_and_identifier(span)
494+
)
495+
remote_resource_type = agentcore_type
496+
remote_resource_identifier = _escape_delimiters(agentcore_identifier) if agentcore_identifier else None
497+
cloudformation_primary_identifier = _escape_delimiters(agentcore_cfn_id) if agentcore_cfn_id else None
469498
elif is_key_present(span, AWS_SECRETSMANAGER_SECRET_ARN):
470499
remote_resource_type = _NORMALIZED_SECRETSMANAGER_SERVICE_NAME + "::Secret"
471500
remote_resource_identifier = _escape_delimiters(
@@ -674,6 +703,201 @@ def _set_span_kind_for_dependency(span: ReadableSpan, attributes: BoundedAttribu
674703
attributes[AWS_SPAN_KIND] = span_kind
675704

676705

706+
def _get_bedrock_agentcore_resource_type_and_identifier(
707+
span: ReadableSpan,
708+
) -> tuple[Optional[str], Optional[str], Optional[str]]:
709+
"""Get BedrockAgentCore resource type, identifier, and CFN primary identifier based on span attributes."""
710+
attrs = span.attributes
711+
if not attrs:
712+
return None, None, None
713+
714+
def format_resource_type(resource_type: Optional[str]) -> Optional[str]:
715+
return f"{_NORMALIZED_BEDROCK_AGENTCORE_SERVICE_NAME}::{resource_type}" if resource_type else None
716+
717+
for handler in [
718+
_handle_browser_attrs,
719+
_handle_gateway_attrs,
720+
_handle_runtime_attrs,
721+
_handle_code_interpreter_attrs,
722+
_handle_identity_attrs,
723+
_handle_memory_attrs,
724+
]:
725+
resource_type, resource_identifier, cfn_primary_identifier = handler(attrs)
726+
if resource_type:
727+
return format_resource_type(resource_type), resource_identifier, cfn_primary_identifier
728+
729+
return None, None, None
730+
731+
732+
def _handle_browser_attrs(attrs: BoundedAttributes) -> tuple[Optional[str], Optional[str], Optional[str]]:
733+
"""
734+
Handler for BedrockAgentCore Browser resources.
735+
Returns (resource_type, resource_identifier, cfn_primary_identifier).
736+
"""
737+
browser_id = attrs.get(GEN_AI_BROWSER_ID)
738+
browser_arn = attrs.get(AWS_BEDROCK_AGENTCORE_BROWSER_ARN)
739+
if browser_id or browser_arn:
740+
agentcore_cfn_identifier = None
741+
if browser_id:
742+
agentcore_cfn_identifier = str(browser_id)
743+
elif browser_arn:
744+
agentcore_cfn_identifier = extract_bedrock_agentcore_resource_id_from_arn(str(browser_arn))
745+
746+
# Uses browser ID as both resource identifier and CFN primary identifier.
747+
# aws.browser.v1 is a managed AWS resource, custom IDs are user-defined resources.
748+
resource_type = "Browser" if agentcore_cfn_identifier == "aws.browser.v1" else "BrowserCustom"
749+
return resource_type, agentcore_cfn_identifier, agentcore_cfn_identifier
750+
return None, None, None
751+
752+
753+
def _handle_gateway_attrs(attrs: BoundedAttributes) -> tuple[Optional[str], Optional[str], Optional[str]]:
754+
"""
755+
Handler for BedrockAgentCore Gateway resources.
756+
Returns (resource_type, resource_identifier, cfn_primary_identifier).
757+
"""
758+
gateway_id = attrs.get(GEN_AI_GATEWAY_ID)
759+
gateway_arn = attrs.get(AWS_BEDROCK_AGENTCORE_GATEWAY_ARN)
760+
gateway_target_id = attrs.get(AWS_GATEWAY_TARGET_ID)
761+
762+
if gateway_target_id:
763+
if gateway_id:
764+
agentcore_cfn_identifier = str(gateway_id)
765+
elif gateway_arn:
766+
agentcore_cfn_identifier = extract_bedrock_agentcore_resource_id_from_arn(str(gateway_arn))
767+
else:
768+
agentcore_cfn_identifier = str(gateway_target_id)
769+
770+
# GatewayTarget contains two primary identifiers: gateway ID and gateway target ID.
771+
# Uses gateway ID and/or gateway target ID as both resource identifier and CFN primary identifier.
772+
# If gateway ID exists or can be extracted from ARN, use it as CFN primary identifier,
773+
# otherwise use target ID.
774+
return "GatewayTarget", agentcore_cfn_identifier, agentcore_cfn_identifier
775+
776+
if gateway_arn or gateway_id:
777+
agentcore_cfn_identifier = None
778+
if gateway_id:
779+
agentcore_cfn_identifier = str(gateway_id)
780+
elif gateway_arn:
781+
agentcore_cfn_identifier = extract_bedrock_agentcore_resource_id_from_arn(str(gateway_arn))
782+
783+
# Uses gateway ID as both resource identifier and CFN primary identifier.
784+
# If gateway ID is not available, extract it from the gateway ARN.
785+
return "Gateway", agentcore_cfn_identifier, agentcore_cfn_identifier
786+
787+
return None, None, None
788+
789+
790+
def _handle_runtime_attrs(attrs: BoundedAttributes) -> tuple[Optional[str], Optional[str], Optional[str]]:
791+
"""
792+
Handler for BedrockAgentCore Runtime resources.
793+
Returns (resource_type, resource_identifier, cfn_primary_identifier).
794+
"""
795+
runtime_id = attrs.get(GEN_AI_RUNTIME_ID)
796+
runtime_arn = attrs.get(AWS_BEDROCK_AGENTCORE_RUNTIME_ARN)
797+
runtime_endpoint_arn = attrs.get(AWS_BEDROCK_AGENTCORE_RUNTIME_ENDPOINT_ARN)
798+
799+
if runtime_endpoint_arn:
800+
agentcore_cfn_identifier = extract_bedrock_agentcore_resource_id_from_arn(str(runtime_endpoint_arn))
801+
802+
# Uses extracted ID as resource identifier and full ARN as CFN primary identifier.
803+
return "RuntimeEndpoint", agentcore_cfn_identifier, str(runtime_endpoint_arn)
804+
805+
if runtime_arn or runtime_id:
806+
agentcore_cfn_identifier = None
807+
if runtime_id:
808+
agentcore_cfn_identifier = str(runtime_id)
809+
elif runtime_arn:
810+
agentcore_cfn_identifier = extract_bedrock_agentcore_resource_id_from_arn(str(runtime_arn))
811+
812+
# Uses runtime ID as both resource identifier and CFN primary identifier.
813+
# If runtime ID is not available, extract it from the runtime ARN.
814+
return "Runtime", agentcore_cfn_identifier, agentcore_cfn_identifier
815+
816+
return None, None, None
817+
818+
819+
def _handle_code_interpreter_attrs(attrs: BoundedAttributes) -> tuple[Optional[str], Optional[str], Optional[str]]:
820+
"""
821+
Handler for BedrockAgentCore CodeInterpreter resources.
822+
Returns (resource_type, resource_identifier, cfn_primary_identifier).
823+
"""
824+
code_interpreter_id = attrs.get(GEN_AI_CODE_INTERPRETER_ID)
825+
code_interpreter_arn = attrs.get(AWS_BEDROCK_AGENTCORE_CODE_INTERPRETER_ARN)
826+
827+
if code_interpreter_id or code_interpreter_arn:
828+
agentcore_cfn_identifier = None
829+
if code_interpreter_id:
830+
agentcore_cfn_identifier = str(code_interpreter_id)
831+
elif code_interpreter_arn:
832+
agentcore_cfn_identifier = extract_bedrock_agentcore_resource_id_from_arn(str(code_interpreter_arn))
833+
834+
# Uses code interpreter ID as both resource identifier and CFN primary identifier.
835+
# aws.codeinterpreter.v1 is a managed AWS resource, custom IDs are user-defined resources.
836+
resource_type = (
837+
"CodeInterpreter" if agentcore_cfn_identifier == "aws.codeinterpreter.v1" else "CodeInterpreterCustom"
838+
)
839+
return resource_type, agentcore_cfn_identifier, agentcore_cfn_identifier
840+
841+
return None, None, None
842+
843+
844+
def _handle_identity_attrs(attrs: BoundedAttributes) -> tuple[Optional[str], Optional[str], Optional[str]]:
845+
"""
846+
Handler for BedrockAgentCore Identity resources.
847+
Returns (resource_type, resource_identifier, cfn_primary_identifier).
848+
"""
849+
credential_arn = attrs.get(AWS_AUTH_CREDENTIAL_PROVIDER_ARN)
850+
851+
if credential_arn:
852+
credential_arn_str = str(credential_arn)
853+
resource_type = None
854+
if "apikeycredentialprovider" in credential_arn_str:
855+
resource_type = "APIKeyCredentialProvider"
856+
elif "oauth2credentialprovider" in credential_arn_str:
857+
resource_type = "OAuth2CredentialProvider"
858+
agentcore_cfn_identifier = extract_bedrock_agentcore_resource_id_from_arn(credential_arn_str)
859+
860+
# Uses extracted ID from credential ARN as both resource identifier and CFN primary identifier.
861+
# Resource type is determined by credential provider type in the ARN.
862+
return resource_type, agentcore_cfn_identifier, agentcore_cfn_identifier
863+
864+
return None, None, None
865+
866+
867+
def _handle_memory_attrs(attrs: BoundedAttributes) -> tuple[Optional[str], Optional[str], Optional[str]]:
868+
"""
869+
Handler for BedrockAgentCore Memory resources.
870+
Returns (resource_type, resource_identifier, cfn_primary_identifier).
871+
"""
872+
memory_id = attrs.get(GEN_AI_MEMORY_ID)
873+
memory_arn = attrs.get(AWS_BEDROCK_AGENTCORE_MEMORY_ARN)
874+
875+
if memory_id or memory_arn:
876+
agentcore_cfn_identifier = None
877+
agentcore_cfn_primary_identifier = None
878+
if memory_id:
879+
agentcore_cfn_identifier = str(memory_id)
880+
if memory_arn:
881+
agentcore_cfn_identifier = agentcore_cfn_identifier or extract_bedrock_agentcore_resource_id_from_arn(
882+
str(memory_arn)
883+
)
884+
agentcore_cfn_primary_identifier = str(memory_arn)
885+
886+
# Uses memory ID as resource identifier and ARN as CFN primary identifier when available.
887+
# If memory ID is not available, extract it from the memory ARN.
888+
return "Memory", agentcore_cfn_identifier, agentcore_cfn_primary_identifier
889+
890+
return None, None, None
891+
892+
893+
def extract_bedrock_agentcore_resource_id_from_arn(arn: str) -> Optional[str]:
894+
"""Extract resource ID from ARN resource part."""
895+
resource_part = RegionalResourceArnParser.extract_resource_name_from_arn(arn)
896+
if not resource_part:
897+
return None
898+
return resource_part.split("/")[-1] if "/" in resource_part else resource_part
899+
900+
677901
def _log_unknown_attribute(attribute_key: str, span: ReadableSpan) -> None:
678902
message: str = "No valid %s value found for %s span %s"
679903
if _logger.isEnabledFor(DEBUG):

aws-opentelemetry-distro/src/amazon/opentelemetry/distro/patches/_bedrock_agentcore_patches.py

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,13 @@
1313
AWS_BEDROCK_AGENTCORE_WORKLOAD_IDENTITY_ARN,
1414
AWS_GATEWAY_TARGET_ID,
1515
)
16+
from amazon.opentelemetry.distro.patches.semconv._incubating.attributes.gen_ai_attributes import (
17+
GEN_AI_BROWSER_ID,
18+
GEN_AI_CODE_INTERPRETER_ID,
19+
GEN_AI_GATEWAY_ID,
20+
GEN_AI_MEMORY_ID,
21+
GEN_AI_RUNTIME_ID,
22+
)
1623
from opentelemetry.instrumentation.botocore.extensions.types import (
1724
_AttributeMapT,
1825
_AwsSdkExtension,
@@ -21,12 +28,6 @@
2128
)
2229
from opentelemetry.trace.span import Span
2330

24-
GEN_AI_RUNTIME_ID = "gen_ai.runtime.id"
25-
GEN_AI_BROWSER_ID = "gen_ai.browser.id"
26-
GEN_AI_CODE_INTERPRETER_ID = "gen_ai.code_interpreter.id"
27-
GEN_AI_MEMORY_ID = "gen_ai.memory.id"
28-
GEN_AI_GATEWAY_ID = "gen_ai.gateway.id"
29-
3031
# Mapping of flattened JSON paths to attribute keys
3132
_ATTRIBUTE_MAPPING = {
3233
"agentRuntimeArn": AWS_BEDROCK_AGENTCORE_RUNTIME_ARN,
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2+
# SPDX-License-Identifier: Apache-2.0
3+
"""
4+
Utility module holding attribute keys for incubating Gen AI semantic conventions.
5+
Remove this once we've contributed them to upstream.
6+
"""
7+
8+
GEN_AI_RUNTIME_ID = "gen_ai.runtime.id"
9+
GEN_AI_BROWSER_ID = "gen_ai.browser.id"
10+
GEN_AI_CODE_INTERPRETER_ID = "gen_ai.code_interpreter.id"
11+
GEN_AI_MEMORY_ID = "gen_ai.memory.id"
12+
GEN_AI_GATEWAY_ID = "gen_ai.gateway.id"

0 commit comments

Comments
 (0)