Skip to content

Commit be08bab

Browse files
author
ADOT Patch workflow
committed
add new bedrock agentcore patching and attributes
1 parent 6eaf909 commit be08bab

File tree

4 files changed

+219
-0
lines changed

4 files changed

+219
-0
lines changed

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

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@
2020
# TODO:Move to Semantic Conventions when these attributes are added.
2121
AWS_AUTH_ACCESS_KEY: str = "aws.auth.account.access_key"
2222
AWS_AUTH_REGION: str = "aws.auth.region"
23+
AWS_AUTH_CREDENTIAL_PROVIDER_ARN: str = "aws.auth.credential_provider.arn"
24+
AWS_GATEWAY_TARGET_ID = "aws.gateway.target.id"
2325
AWS_SQS_QUEUE_URL: str = "aws.sqs.queue.url"
2426
AWS_SQS_QUEUE_NAME: str = "aws.sqs.queue.name"
2527
AWS_KINESIS_STREAM_ARN: str = "aws.kinesis.stream.arn"
@@ -41,3 +43,10 @@
4143
AWS_REMOTE_RESOURCE_ACCOUNT_ID: str = "aws.remote.resource.account.id"
4244
AWS_REMOTE_RESOURCE_REGION: str = "aws.remote.resource.region"
4345
AWS_SERVICE_TYPE: str = "aws.service.type"
46+
AWS_BEDROCK_AGENTCORE_RUNTIME_ARN: str = "aws.bedrock.agentcore.runtime.arn"
47+
AWS_BEDROCK_AGENTCORE_RUNTIME_ENDPOINT_ARN: str = "aws.bedrock.agentcore.runtime_endpoint.arn"
48+
AWS_BEDROCK_AGENTCORE_CODE_INTERPRETER_ARN: str = "aws.bedrock.agentcore.code_interpreter.arn"
49+
AWS_BEDROCK_AGENTCORE_BROWSER_ARN: str = "aws.bedrock.agentcore.browser.arn"
50+
AWS_BEDROCK_AGENTCORE_MEMORY_ARN: str = "aws.bedrock.agentcore.memory.arn"
51+
AWS_BEDROCK_AGENTCORE_GATEWAY_ARN: str = "aws.bedrock.agentcore.gateway.arn"
52+
AWS_BEDROCK_AGENTCORE_WORKLOAD_IDENTITY_ARN: str = "aws.bedrock.agentcore.identity.workload_identity.arn"
Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
# Copyright The OpenTelemetry Authors
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
from typing import Any, Dict
15+
16+
from amazon.opentelemetry.distro._aws_attribute_keys import (
17+
AWS_AUTH_CREDENTIAL_PROVIDER_ARN,
18+
AWS_BEDROCK_AGENTCORE_BROWSER_ARN,
19+
AWS_BEDROCK_AGENTCORE_CODE_INTERPRETER_ARN,
20+
AWS_BEDROCK_AGENTCORE_GATEWAY_ARN,
21+
AWS_BEDROCK_AGENTCORE_MEMORY_ARN,
22+
AWS_BEDROCK_AGENTCORE_RUNTIME_ARN,
23+
AWS_BEDROCK_AGENTCORE_RUNTIME_ENDPOINT_ARN,
24+
AWS_BEDROCK_AGENTCORE_WORKLOAD_IDENTITY_ARN,
25+
AWS_GATEWAY_TARGET_ID,
26+
)
27+
from opentelemetry.instrumentation.botocore.extensions.types import (
28+
_AttributeMapT,
29+
_AwsSdkExtension,
30+
_BotocoreInstrumentorContext,
31+
_BotoResultT,
32+
)
33+
from opentelemetry.trace.span import Span
34+
35+
GEN_AI_RUNTIME_ID = "gen_ai.runtime.id"
36+
GEN_AI_BROWSER_ID = "gen_ai.browser.id"
37+
GEN_AI_CODE_INTERPRETER_ID = "gen_ai.code_interpreter.id"
38+
GEN_AI_MEMORY_ID = "gen_ai.memory.id"
39+
GEN_AI_GATEWAY_ID = "gen_ai.gateway.id"
40+
41+
# Mapping of flattened JSON paths to attribute keys
42+
_ATTRIBUTE_MAPPING = {
43+
"agentRuntimeArn": AWS_BEDROCK_AGENTCORE_RUNTIME_ARN,
44+
"agentRuntimeEndpointArn": AWS_BEDROCK_AGENTCORE_RUNTIME_ENDPOINT_ARN,
45+
"agentRuntimeId": GEN_AI_RUNTIME_ID,
46+
"browserArn": AWS_BEDROCK_AGENTCORE_BROWSER_ARN,
47+
"browserId": GEN_AI_BROWSER_ID,
48+
"browserIdentifier": GEN_AI_BROWSER_ID,
49+
"codeInterpreterArn": AWS_BEDROCK_AGENTCORE_CODE_INTERPRETER_ARN,
50+
"codeInterpreterId": GEN_AI_CODE_INTERPRETER_ID,
51+
"codeInterpreterIdentifier": GEN_AI_CODE_INTERPRETER_ID,
52+
"gatewayArn": AWS_BEDROCK_AGENTCORE_GATEWAY_ARN,
53+
"gatewayId": GEN_AI_GATEWAY_ID,
54+
"gatewayIdentifier": GEN_AI_GATEWAY_ID,
55+
"targetId": AWS_GATEWAY_TARGET_ID,
56+
"memory.arn": AWS_BEDROCK_AGENTCORE_MEMORY_ARN,
57+
"memory.id": GEN_AI_MEMORY_ID,
58+
"memoryId": GEN_AI_MEMORY_ID,
59+
"credentialProviderArn": AWS_AUTH_CREDENTIAL_PROVIDER_ARN,
60+
"workloadIdentityArn": AWS_BEDROCK_AGENTCORE_WORKLOAD_IDENTITY_ARN,
61+
"workloadIdentityDetails.workloadIdentityArn": AWS_BEDROCK_AGENTCORE_WORKLOAD_IDENTITY_ARN,
62+
}
63+
64+
65+
class _BedrockAgentCoreExtension(_AwsSdkExtension):
66+
def extract_attributes(self, attributes: _AttributeMapT):
67+
extracted_attrs = self._extract_attributes(self._call_context.params)
68+
attributes.update(extracted_attrs)
69+
70+
def on_success(
71+
self,
72+
span: Span,
73+
result: _BotoResultT,
74+
instrumentor_context: _BotocoreInstrumentorContext,
75+
):
76+
if span is None or not span.is_recording():
77+
return
78+
79+
extracted_attrs = self._extract_attributes(result)
80+
for attr_name, attr_value in extracted_attrs.items():
81+
span.set_attribute(attr_name, attr_value)
82+
83+
@staticmethod
84+
def _extract_attributes(params: Dict[str, Any]):
85+
"""Extracts all Bedrock AgentCore attributes using mapping-based traversal"""
86+
attrs = {}
87+
for path, attr_key in _ATTRIBUTE_MAPPING.items():
88+
value = _BedrockAgentCoreExtension._get_nested_value(params, path)
89+
if value:
90+
attrs[attr_key] = value
91+
return attrs
92+
93+
@staticmethod
94+
def _get_nested_value(data: Dict[str, Any], path: str):
95+
"""Get value from nested dictionary using dot notation path"""
96+
keys = path.split(".")
97+
value = data
98+
for key in keys:
99+
if isinstance(value, dict) and key in value:
100+
value = value[key]
101+
else:
102+
return None
103+
return value

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

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,9 @@
2323
AWS_STEPFUNCTIONS_ACTIVITY_ARN,
2424
AWS_STEPFUNCTIONS_STATEMACHINE_ARN,
2525
)
26+
from amazon.opentelemetry.distro.patches._bedrock_agentcore_patches import ( # noqa # pylint: disable=unused-import
27+
_BedrockAgentCoreExtension,
28+
)
2629
from amazon.opentelemetry.distro.patches._bedrock_patches import ( # noqa # pylint: disable=unused-import
2730
_BedrockAgentExtension,
2831
_BedrockAgentRuntimeExtension,
@@ -247,6 +250,10 @@ def _apply_botocore_bedrock_patch() -> None: # pylint: disable=too-many-stateme
247250
_KNOWN_EXTENSIONS["bedrock"] = _lazy_load(".", "_BedrockExtension")
248251
_KNOWN_EXTENSIONS["bedrock-agent"] = _lazy_load(".", "_BedrockAgentExtension")
249252
_KNOWN_EXTENSIONS["bedrock-agent-runtime"] = _lazy_load(".", "_BedrockAgentRuntimeExtension")
253+
_KNOWN_EXTENSIONS["bedrock-agentcore"] = _lazy_load(".._bedrock_agentcore_patches", "_BedrockAgentCoreExtension")
254+
_KNOWN_EXTENSIONS["bedrock-agentcore-control"] = _lazy_load(
255+
".._bedrock_agentcore_patches", "_BedrockAgentCoreExtension"
256+
)
250257

251258
# TODO: The following code is to patch bedrock-runtime bugs that are fixed in
252259
# opentelemetry-instrumentation-botocore==0.56b0 in these PRs:

aws-opentelemetry-distro/tests/amazon/opentelemetry/distro/test_instrumentation_patch.py renamed to aws-opentelemetry-distro/tests/amazon/opentelemetry/distro/patches/test_instrumentation_patch.py

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,24 @@
1010

1111
import opentelemetry.sdk.extension.aws.resource.ec2 as ec2_resource
1212
import opentelemetry.sdk.extension.aws.resource.eks as eks_resource
13+
from amazon.opentelemetry.distro._aws_attribute_keys import (
14+
AWS_AUTH_CREDENTIAL_PROVIDER_ARN,
15+
AWS_BEDROCK_AGENTCORE_BROWSER_ARN,
16+
AWS_BEDROCK_AGENTCORE_CODE_INTERPRETER_ARN,
17+
AWS_BEDROCK_AGENTCORE_GATEWAY_ARN,
18+
AWS_BEDROCK_AGENTCORE_MEMORY_ARN,
19+
AWS_BEDROCK_AGENTCORE_RUNTIME_ARN,
20+
AWS_BEDROCK_AGENTCORE_RUNTIME_ENDPOINT_ARN,
21+
AWS_BEDROCK_AGENTCORE_WORKLOAD_IDENTITY_ARN,
22+
AWS_GATEWAY_TARGET_ID,
23+
)
24+
from amazon.opentelemetry.distro.patches._bedrock_agentcore_patches import (
25+
GEN_AI_BROWSER_ID,
26+
GEN_AI_CODE_INTERPRETER_ID,
27+
GEN_AI_GATEWAY_ID,
28+
GEN_AI_MEMORY_ID,
29+
GEN_AI_RUNTIME_ID,
30+
)
1331
from amazon.opentelemetry.distro.patches._instrumentation_patch import (
1432
AWS_GEVENT_PATCH_MODULES,
1533
apply_instrumentation_patches,
@@ -38,6 +56,20 @@
3856
_LAMBDA_FUNCTION_NAME: str = "lambdaFunctionName"
3957
_LAMBDA_SOURCE_MAPPING_ID: str = "lambdaEventSourceMappingID"
4058
_TABLE_ARN: str = "arn:aws:dynamodb:us-west-2:123456789012:table/testTable"
59+
_AGENTCORE_RUNTIME_ARN: str = "arn:aws:bedrock-agentcore:us-east-1:123456789012:runtime/test-runtime"
60+
_AGENTCORE_RUNTIME_ENDPOINT_ARN: str = "arn:aws:bedrock-agentcore:us-east-1:123456789012:runtime-endpoint/test-endpoint"
61+
_AGENTCORE_RUNTIME_ID: str = "test-runtime-123"
62+
_AGENTCORE_BROWSER_ARN: str = "arn:aws:bedrock-agentcore:us-east-1:123456789012:browser/test-browser"
63+
_AGENTCORE_BROWSER_ID: str = "agentBrowser-123456789"
64+
_AGENTCORE_CODE_INTERPRETER_ARN: str = "arn:aws:bedrock-agentcore:us-east-1:123456789012:code-interpreter/test-ci"
65+
_AGENTCORE_CODE_INTERPRETER_ID: str = "agentCodeInterpreter-123456789"
66+
_AGENTCORE_GATEWAY_ARN: str = "arn:aws:bedrock-agentcore:us-east-1:123456789012:gateway/test-gateway"
67+
_AGENTCORE_GATEWAY_ID: str = "agentGateway-123456789"
68+
_AGENTCORE_TARGET_ID: str = "target-123456789"
69+
_AGENTCORE_MEMORY_ARN: str = "arn:aws:bedrock-agentcore:us-east-1:123456789012:memory/test-memory"
70+
_AGENTCORE_MEMORY_ID: str = "agentMemory-123456789"
71+
_AGENTCORE_CREDENTIAL_PROVIDER_ARN: str = "arn:aws:bedrock-agentcore:us-east-1:123456789012:credential-provider/test-cp"
72+
_AGENTCORE_WORKLOAD_IDENTITY_ARN: str = "arn:aws:bedrock-agentcore:us-east-1:123456789012:workload-identity/test-wi"
4173

4274
# Patch names
4375
IMPORTLIB_METADATA_VERSION_PATCH: str = "amazon.opentelemetry.distro._utils.version"
@@ -160,6 +192,14 @@ def _test_unpatched_botocore_instrumentation(self):
160192
"bedrock-agent-runtime" in _KNOWN_EXTENSIONS, "Upstream has added a Bedrock Agent Runtime extension"
161193
)
162194

195+
# Bedrock AgentCore
196+
self.assertFalse("bedrock-agentcore" in _KNOWN_EXTENSIONS, "Upstream has added a Bedrock AgentCore extension")
197+
198+
# Bedrock AgentCore Control
199+
self.assertFalse(
200+
"bedrock-agentcore-control" in _KNOWN_EXTENSIONS, "Upstream has added a Bedrock AgentCore Control extension"
201+
)
202+
163203
# BedrockRuntime
164204
self.assertTrue("bedrock-runtime" in _KNOWN_EXTENSIONS, "Upstream has added a bedrock-runtime extension")
165205

@@ -237,6 +277,41 @@ def _test_patched_botocore_instrumentation(self):
237277
bedrock_agent_runtime_sucess_attributes: Dict[str, str] = _do_on_success_bedrock("bedrock-agent-runtime")
238278
self.assertEqual(len(bedrock_agent_runtime_sucess_attributes), 0)
239279

280+
# Bedrock AgentCore
281+
self.assertTrue("bedrock-agentcore" in _KNOWN_EXTENSIONS)
282+
bedrock_agentcore_attributes: Dict[str, str] = _do_extract_bedrock_agentcore_attributes()
283+
# Runtime attributes
284+
self.assertEqual(bedrock_agentcore_attributes[AWS_BEDROCK_AGENTCORE_RUNTIME_ARN], _AGENTCORE_RUNTIME_ARN)
285+
self.assertEqual(
286+
bedrock_agentcore_attributes[AWS_BEDROCK_AGENTCORE_RUNTIME_ENDPOINT_ARN], _AGENTCORE_RUNTIME_ENDPOINT_ARN
287+
)
288+
self.assertEqual(bedrock_agentcore_attributes[GEN_AI_RUNTIME_ID], _AGENTCORE_RUNTIME_ID)
289+
# Browser attributes
290+
self.assertEqual(bedrock_agentcore_attributes[AWS_BEDROCK_AGENTCORE_BROWSER_ARN], _AGENTCORE_BROWSER_ARN)
291+
self.assertEqual(bedrock_agentcore_attributes[GEN_AI_BROWSER_ID], _AGENTCORE_BROWSER_ID)
292+
# Code interpreter attributes
293+
self.assertEqual(
294+
bedrock_agentcore_attributes[AWS_BEDROCK_AGENTCORE_CODE_INTERPRETER_ARN], _AGENTCORE_CODE_INTERPRETER_ARN
295+
)
296+
self.assertEqual(bedrock_agentcore_attributes[GEN_AI_CODE_INTERPRETER_ID], _AGENTCORE_CODE_INTERPRETER_ID)
297+
# Gateway attributes
298+
self.assertEqual(bedrock_agentcore_attributes[AWS_BEDROCK_AGENTCORE_GATEWAY_ARN], _AGENTCORE_GATEWAY_ARN)
299+
self.assertEqual(bedrock_agentcore_attributes[GEN_AI_GATEWAY_ID], _AGENTCORE_GATEWAY_ID)
300+
self.assertEqual(bedrock_agentcore_attributes[AWS_GATEWAY_TARGET_ID], _AGENTCORE_TARGET_ID)
301+
# Memory attributes
302+
self.assertEqual(bedrock_agentcore_attributes[GEN_AI_MEMORY_ID], _AGENTCORE_MEMORY_ID)
303+
self.assertEqual(bedrock_agentcore_attributes[AWS_BEDROCK_AGENTCORE_MEMORY_ARN], _AGENTCORE_MEMORY_ARN)
304+
# Auth and identity attributes
305+
self.assertEqual(
306+
bedrock_agentcore_attributes[AWS_AUTH_CREDENTIAL_PROVIDER_ARN], _AGENTCORE_CREDENTIAL_PROVIDER_ARN
307+
)
308+
self.assertEqual(
309+
bedrock_agentcore_attributes[AWS_BEDROCK_AGENTCORE_WORKLOAD_IDENTITY_ARN], _AGENTCORE_WORKLOAD_IDENTITY_ARN
310+
)
311+
312+
# Bedrock AgentCore Control
313+
self.assertTrue("bedrock-agentcore-control" in _KNOWN_EXTENSIONS)
314+
240315
# BedrockRuntime
241316
self.assertTrue("bedrock-runtime" in _KNOWN_EXTENSIONS)
242317

@@ -854,6 +929,31 @@ def _do_extract_lambda_attributes() -> Dict[str, str]:
854929
return _do_extract_attributes(service_name, params)
855930

856931

932+
def _do_extract_bedrock_agentcore_attributes() -> Dict[str, str]:
933+
service_name: str = "bedrock-agentcore"
934+
params: Dict[str, Any] = {
935+
"agentRuntimeArn": _AGENTCORE_RUNTIME_ARN,
936+
"agentRuntimeEndpointArn": _AGENTCORE_RUNTIME_ENDPOINT_ARN,
937+
"agentRuntimeId": _AGENTCORE_RUNTIME_ID,
938+
"browserArn": _AGENTCORE_BROWSER_ARN,
939+
"browserId": _AGENTCORE_BROWSER_ID,
940+
"browserIdentifier": _AGENTCORE_BROWSER_ID,
941+
"codeInterpreterArn": _AGENTCORE_CODE_INTERPRETER_ARN,
942+
"codeInterpreterId": _AGENTCORE_CODE_INTERPRETER_ID,
943+
"codeInterpreterIdentifier": _AGENTCORE_CODE_INTERPRETER_ID,
944+
"gatewayArn": _AGENTCORE_GATEWAY_ARN,
945+
"gatewayId": _AGENTCORE_GATEWAY_ID,
946+
"gatewayIdentifier": _AGENTCORE_GATEWAY_ID,
947+
"targetId": _AGENTCORE_TARGET_ID,
948+
"memoryId": _AGENTCORE_MEMORY_ID,
949+
"credentialProviderArn": _AGENTCORE_CREDENTIAL_PROVIDER_ARN,
950+
"workloadIdentityArn": _AGENTCORE_WORKLOAD_IDENTITY_ARN,
951+
"memory": {"arn": _AGENTCORE_MEMORY_ARN, "id": _AGENTCORE_MEMORY_ID},
952+
"workloadIdentityDetails": {"workloadIdentityArn": _AGENTCORE_WORKLOAD_IDENTITY_ARN},
953+
}
954+
return _do_extract_attributes(service_name, params)
955+
956+
857957
def _do_extract_attributes(service_name: str, params: Dict[str, Any], operation: str = None) -> Dict[str, str]:
858958
mock_call_context: MagicMock = MagicMock()
859959
mock_call_context.params = params

0 commit comments

Comments
 (0)