feat: AWS SDK v2 Secrets Manager auto-instrumentation support (#14001)

Co-authored-by: Lauri Tulmin <ltulmin@splunk.com>
This commit is contained in:
Luke (GuangHui) Zhang 2025-06-12 10:19:29 -07:00 committed by GitHub
parent 70588cd360
commit 4a2b49fbef
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 84 additions and 5 deletions

View File

@ -121,9 +121,10 @@ dependencies {
testLibrary("software.amazon.awssdk:lambda:2.2.0")
testLibrary("software.amazon.awssdk:rds:2.2.0")
testLibrary("software.amazon.awssdk:s3:2.2.0")
testLibrary("software.amazon.awssdk:sqs:2.2.0")
testLibrary("software.amazon.awssdk:sns:2.2.0")
testLibrary("software.amazon.awssdk:ses:2.2.0")
testLibrary("software.amazon.awssdk:secretsmanager:2.2.0")
testLibrary("software.amazon.awssdk:sns:2.2.0")
testLibrary("software.amazon.awssdk:sqs:2.2.0")
}
val latestDepTest = findProperty("testLatestDeps") as Boolean

View File

@ -18,8 +18,9 @@ dependencies {
testLibrary("software.amazon.awssdk:lambda:2.2.0")
testLibrary("software.amazon.awssdk:rds:2.2.0")
testLibrary("software.amazon.awssdk:s3:2.2.0")
testLibrary("software.amazon.awssdk:sqs:2.2.0")
testLibrary("software.amazon.awssdk:secretsmanager:2.2.0")
testLibrary("software.amazon.awssdk:sns:2.2.0")
testLibrary("software.amazon.awssdk:sqs:2.2.0")
}
tasks {

View File

@ -26,6 +26,7 @@ dependencies {
testLibrary("software.amazon.awssdk:kinesis:2.2.0")
testLibrary("software.amazon.awssdk:rds:2.2.0")
testLibrary("software.amazon.awssdk:s3:2.2.0")
testLibrary("software.amazon.awssdk:secretsmanager:2.2.0")
testLibrary("software.amazon.awssdk:ses:2.2.0")
}

View File

@ -9,6 +9,7 @@ import static io.opentelemetry.instrumentation.awssdk.v2_2.internal.AwsSdkReques
import static io.opentelemetry.instrumentation.awssdk.v2_2.internal.AwsSdkRequestType.DYNAMODB;
import static io.opentelemetry.instrumentation.awssdk.v2_2.internal.AwsSdkRequestType.KINESIS;
import static io.opentelemetry.instrumentation.awssdk.v2_2.internal.AwsSdkRequestType.S3;
import static io.opentelemetry.instrumentation.awssdk.v2_2.internal.AwsSdkRequestType.SECRETSMANAGER;
import static io.opentelemetry.instrumentation.awssdk.v2_2.internal.AwsSdkRequestType.SNS;
import static io.opentelemetry.instrumentation.awssdk.v2_2.internal.AwsSdkRequestType.SQS;
import static io.opentelemetry.instrumentation.awssdk.v2_2.internal.FieldMapping.request;
@ -35,6 +36,7 @@ enum AwsSdkRequest {
SnsRequest(SNS, "SnsRequest"),
SqsRequest(SQS, "SqsRequest"),
KinesisRequest(KINESIS, "KinesisRequest"),
SecretsManagerRequest(SECRETSMANAGER, "SecretsManagerRequest"),
// specific requests
BatchGetItem(
DYNAMODB,

View File

@ -5,7 +5,9 @@
package io.opentelemetry.instrumentation.awssdk.v2_2.internal;
import static io.opentelemetry.api.common.AttributeKey.stringKey;
import static io.opentelemetry.instrumentation.awssdk.v2_2.internal.FieldMapping.request;
import static io.opentelemetry.instrumentation.awssdk.v2_2.internal.FieldMapping.response;
import io.opentelemetry.api.common.AttributeKey;
import java.util.Collections;
@ -18,6 +20,7 @@ enum AwsSdkRequestType {
KINESIS(request("aws.stream.name", "StreamName")),
DYNAMODB(request("aws.table.name", "TableName")),
BEDROCK_RUNTIME(),
SECRETSMANAGER(response(AttributeKeys.AWS_SECRETSMANAGER_SECRET_ARN.getKey(), "ARN")),
SNS(
/*
* Only one of TopicArn and TargetArn are permitted on an SNS request.
@ -38,6 +41,10 @@ enum AwsSdkRequestType {
}
private static class AttributeKeys {
// Copied from AwsIncubatingAttributes
static final AttributeKey<String> AWS_SECRETSMANAGER_SECRET_ARN =
stringKey("aws.secretsmanager.secret.arn");
// copied from MessagingIncubatingAttributes
static final AttributeKey<String> MESSAGING_DESTINATION_NAME =
AttributeKey.stringKey("messaging.destination.name");

View File

@ -18,9 +18,10 @@ dependencies {
compileOnly("software.amazon.awssdk:lambda:2.2.0")
compileOnly("software.amazon.awssdk:rds:2.2.0")
compileOnly("software.amazon.awssdk:s3:2.2.0")
compileOnly("software.amazon.awssdk:sqs:2.2.0")
compileOnly("software.amazon.awssdk:sns:2.2.0")
compileOnly("software.amazon.awssdk:secretsmanager:2.2.0")
compileOnly("software.amazon.awssdk:ses:2.2.0")
compileOnly("software.amazon.awssdk:sns:2.2.0")
compileOnly("software.amazon.awssdk:sqs:2.2.0")
// needed for SQS - using emq directly as localstack references emq v0.15.7 ie WITHOUT AWS trace header propagation
implementation("org.elasticmq:elasticmq-rest-sqs_2.13")

View File

@ -14,6 +14,7 @@ import static io.opentelemetry.semconv.ServerAttributes.SERVER_ADDRESS;
import static io.opentelemetry.semconv.ServerAttributes.SERVER_PORT;
import static io.opentelemetry.semconv.UrlAttributes.URL_FULL;
import static io.opentelemetry.semconv.incubating.AwsIncubatingAttributes.AWS_REQUEST_ID;
import static io.opentelemetry.semconv.incubating.AwsIncubatingAttributes.AWS_SECRETSMANAGER_SECRET_ARN;
import static io.opentelemetry.semconv.incubating.MessagingIncubatingAttributes.MESSAGING_DESTINATION_NAME;
import static io.opentelemetry.semconv.incubating.MessagingIncubatingAttributes.MESSAGING_MESSAGE_ID;
import static io.opentelemetry.semconv.incubating.MessagingIncubatingAttributes.MESSAGING_OPERATION;
@ -79,6 +80,12 @@ import software.amazon.awssdk.services.s3.S3Client;
import software.amazon.awssdk.services.s3.S3ClientBuilder;
import software.amazon.awssdk.services.s3.model.CreateBucketRequest;
import software.amazon.awssdk.services.s3.model.GetObjectRequest;
import software.amazon.awssdk.services.secretsmanager.SecretsManagerAsyncClient;
import software.amazon.awssdk.services.secretsmanager.SecretsManagerAsyncClientBuilder;
import software.amazon.awssdk.services.secretsmanager.SecretsManagerClient;
import software.amazon.awssdk.services.secretsmanager.SecretsManagerClientBuilder;
import software.amazon.awssdk.services.secretsmanager.model.GetSecretValueRequest;
import software.amazon.awssdk.services.secretsmanager.model.GetSecretValueResponse;
import software.amazon.awssdk.services.sns.SnsAsyncClient;
import software.amazon.awssdk.services.sns.SnsAsyncClientBuilder;
import software.amazon.awssdk.services.sns.SnsClient;
@ -112,6 +119,18 @@ public abstract class AbstractAws2ClientTest extends AbstractAws2ClientCoreTest
+ " <ResponseMetadata><RequestId>0ac9cda2-bbf4-11d3-f92b-31fa5e8dbc99</RequestId></ResponseMetadata>"
+ "</DeleteOptionGroupResponse>";
private static final String secretsManagerBodyContent =
"{"
+ " \"ARN\": \"arn:aws:secretsmanager:us-east-1:123456789012:secret:MySecretFromCLI-sNkBwD\","
+ " \"Name\": \"MySecretFromCLI\","
+ " \"VersionId\": \"9959b95b-1234-5678-a19b-a4b0315ca5aa\","
+ " \"SecretString\": \"super-secret-value\","
+ " \"VersionStages\": ["
+ " \"AWSCURRENT\""
+ " ],"
+ " \"CreatedDate\": \"1.523477145713E9\""
+ "}";
private static void assumeSupportedConfig(String operation) {
Assumptions.assumeFalse(
operation.equals("SendMessage") && isSqsAttributeInjectionEnabled(),
@ -214,6 +233,13 @@ public abstract class AbstractAws2ClientTest extends AbstractAws2ClientCoreTest
equalTo(MESSAGING_SYSTEM, AWS_SQS))));
}
if (service.equals("SecretsManager")) {
attributes.add(
equalTo(
AWS_SECRETSMANAGER_SECRET_ARN,
"arn:aws:secretsmanager:us-east-1:123456789012:secret:MySecretFromCLI-sNkBwD"));
}
String evaluatedOperation;
SpanKind operationKind;
if (operation.equals("SendMessage")) {
@ -722,4 +748,44 @@ public abstract class AbstractAws2ClientTest extends AbstractAws2ClientCoreTest
assertThat(Context.current()).isEqualTo(Context.root());
}
@Test
void testSecretsManagerSendOperationRequestWithBuilder() {
SecretsManagerClientBuilder builder = SecretsManagerClient.builder();
configureSdkClient(builder);
SecretsManagerClient client =
builder
.endpointOverride(clientUri)
.region(Region.AP_NORTHEAST_1)
.credentialsProvider(CREDENTIALS_PROVIDER)
.build();
server.enqueue(
HttpResponse.of(HttpStatus.OK, MediaType.PLAIN_TEXT_UTF_8, secretsManagerBodyContent));
Object response =
client.getSecretValue(GetSecretValueRequest.builder().secretId("MySecretFromCLI").build());
assertThat(response.getClass().getSimpleName())
.satisfies(
v -> assertThat(v).isEqualTo("GetSecretValueResponse"),
v -> assertThat(response).isInstanceOf(GetSecretValueResponse.class));
clientAssertions("SecretsManager", "GetSecretValue", "POST", response, "UNKNOWN");
}
@Test
void testSecretsManagerAsyncSendOperationRequestWithBuilder() {
SecretsManagerAsyncClientBuilder builder = SecretsManagerAsyncClient.builder();
configureSdkClient(builder);
SecretsManagerAsyncClient client =
builder
.endpointOverride(clientUri)
.region(Region.AP_NORTHEAST_1)
.credentialsProvider(CREDENTIALS_PROVIDER)
.build();
server.enqueue(
HttpResponse.of(HttpStatus.OK, MediaType.PLAIN_TEXT_UTF_8, secretsManagerBodyContent));
Object response =
client.getSecretValue(GetSecretValueRequest.builder().secretId("MySecretFromCLI").build());
clientAssertions("SecretsManager", "GetSecretValue", "POST", response, "UNKNOWN");
}
}