Skip to content

Commit b232b9a

Browse files
lukeina2ztammy-baylis-swiemdnetoxrmx
authored
botocore: Add support for AWS Secrets Manager semantic convention attribute (#3765)
* botocore: Add support for AWS Secrets Manager semantic convention attribute AWS Secrets Manager defines semantic convention attribute: AWS_SECRETSMANAGER_SECRET_ARN: Final = "aws.secretsmanager.secret.arn" https://github.com/open-telemetry/semantic-conventions/blob/main/docs/registry/attributes/aws.md#amazon-secrets-manager-attributes Currently, this attribute is not set in the botocore instrumentation library. This PR adds support for them by extracting values from both Request and Response objects. Tests Added new unit tests (passing). Verified with: tox -e py312-test-instrumentation-botocore tox -e spellcheck tox -e lint-instrumentation-botocore tox -e ruff Backward Compatibility This change is backward compatible. It only adds instrumentation for additional AWS resources and does not modify existing behavior in the auto-instrumentation library. * add ChangeLog. * Update instrumentation/opentelemetry-instrumentation-botocore/src/opentelemetry/instrumentation/botocore/extensions/secretsmanager.py Co-authored-by: Tammy Baylis <[email protected]> * Update instrumentation/opentelemetry-instrumentation-botocore/tests/test_botocore_secretsmanager.py --------- Co-authored-by: Tammy Baylis <[email protected]> Co-authored-by: Emídio Neto <[email protected]> Co-authored-by: Riccardo Magliocchetti <[email protected]>
1 parent 18c3365 commit b232b9a

File tree

4 files changed

+140
-0
lines changed

4 files changed

+140
-0
lines changed

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1111
1212
## Unreleased
1313

14+
### Fixed
15+
16+
### Added
17+
- `opentelemetry-instrumentation`: botocore: Add support for AWS Secrets Manager semantic convention attribute
18+
([#3765](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/3765))
19+
1420
## Version 1.37.0/0.58b0 (2025-09-11)
1521

1622
### Fixed

instrumentation/opentelemetry-instrumentation-botocore/src/opentelemetry/instrumentation/botocore/extensions/__init__.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,9 @@ def loader():
3535
"bedrock-runtime": _lazy_load(".bedrock", "_BedrockRuntimeExtension"),
3636
"dynamodb": _lazy_load(".dynamodb", "_DynamoDbExtension"),
3737
"lambda": _lazy_load(".lmbd", "_LambdaExtension"),
38+
"secretsmanager": _lazy_load(
39+
".secretsmanager", "_SecretsManagerExtension"
40+
),
3841
"stepfunctions": _lazy_load(".sfns", "_StepFunctionsExtension"),
3942
"sns": _lazy_load(".sns", "_SnsExtension"),
4043
"sqs": _lazy_load(".sqs", "_SqsExtension"),
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
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 opentelemetry.instrumentation.botocore.extensions.types import (
15+
_AttributeMapT,
16+
_AwsSdkExtension,
17+
_BotocoreInstrumentorContext,
18+
_BotoResultT,
19+
)
20+
from opentelemetry.semconv._incubating.attributes.aws_attributes import (
21+
AWS_SECRETSMANAGER_SECRET_ARN,
22+
)
23+
from opentelemetry.trace.span import Span
24+
25+
26+
class _SecretsManagerExtension(_AwsSdkExtension):
27+
def extract_attributes(self, attributes: _AttributeMapT):
28+
"""
29+
SecretId is extracted if a secret ARN, the function extracts the attribute
30+
only if the SecretId parameter is provided as an arn which starts with
31+
`arn:aws:secretsmanager:`
32+
"""
33+
secret_id = self._call_context.params.get("SecretId")
34+
if secret_id and secret_id.startswith("arn:aws:secretsmanager:"):
35+
attributes[AWS_SECRETSMANAGER_SECRET_ARN] = secret_id
36+
37+
def on_success(
38+
self,
39+
span: Span,
40+
result: _BotoResultT,
41+
instrumentor_context: _BotocoreInstrumentorContext,
42+
):
43+
secret_arn = result.get("ARN")
44+
if secret_arn:
45+
span.set_attribute(AWS_SECRETSMANAGER_SECRET_ARN, secret_arn)
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
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+
15+
import botocore.session
16+
from moto import mock_aws
17+
18+
from opentelemetry.instrumentation.botocore import BotocoreInstrumentor
19+
from opentelemetry.semconv._incubating.attributes.aws_attributes import (
20+
AWS_SECRETSMANAGER_SECRET_ARN,
21+
)
22+
from opentelemetry.test.test_base import TestBase
23+
24+
25+
class TestSecretsManagerExtension(TestBase):
26+
def setUp(self):
27+
super().setUp()
28+
BotocoreInstrumentor().instrument()
29+
session = botocore.session.get_session()
30+
session.set_credentials(
31+
access_key="access-key", secret_key="secret-key"
32+
)
33+
self.region = "us-west-2"
34+
self.client = session.create_client(
35+
"secretsmanager", region_name=self.region
36+
)
37+
38+
def tearDown(self):
39+
super().tearDown()
40+
BotocoreInstrumentor().uninstrument()
41+
42+
def create_secret_and_get_arn(self, name: str = "test-secret") -> str:
43+
"""
44+
Create a secret in mocked Secrets Manager and return its ARN.
45+
"""
46+
# Clear spans before creating secret for helper method
47+
self.memory_exporter.clear()
48+
response = self.client.create_secret(
49+
Name=name, SecretString="test-secret-value"
50+
)
51+
return response["ARN"]
52+
53+
@mock_aws
54+
def test_tag_resource_with_arn(self):
55+
secret_arn = self.create_secret_and_get_arn()
56+
57+
self.client.tag_resource(
58+
SecretId=secret_arn, Tags=[{"Key": "Environment", "Value": "Test"}]
59+
)
60+
61+
spans = self.memory_exporter.get_finished_spans()
62+
assert spans
63+
self.assertEqual(len(spans), 2)
64+
span = spans[1] # tag_resource span
65+
self.assertEqual(
66+
span.attributes[AWS_SECRETSMANAGER_SECRET_ARN],
67+
secret_arn,
68+
)
69+
70+
@mock_aws
71+
def test_create_secret(self):
72+
secret_name = "test-secret"
73+
response = self.client.create_secret(
74+
Name=secret_name, SecretString="test-secret-value"
75+
)
76+
secret_arn = response["ARN"]
77+
78+
spans = self.memory_exporter.get_finished_spans()
79+
assert spans
80+
self.assertEqual(len(spans), 1)
81+
span = spans[0] # create_secret span
82+
# Should capture ARN from response
83+
self.assertEqual(
84+
span.attributes[AWS_SECRETSMANAGER_SECRET_ARN],
85+
secret_arn,
86+
)

0 commit comments

Comments
 (0)