Skip to content

Commit 87aae70

Browse files
committed
feat: Add auto-instrumentation support for AWS Secrets Manager SDK v1
This PR introduces auto-instrumentation support for the following AWS resource: AWS Secrets Manager SDK v1 Tests Run: ./gradlew spotlessCheck ./gradlew clean assemble ./gradlew instrumentation:check ./gradlew :smoke-tests:test All newly added tests pass, and no regression issues were found. Backward Compatibility: This change is backward compatible. It adds instrumentation for an additional AWS resource without modifying existing behavior in the auto-instrumentation library.
1 parent c3e9e59 commit 87aae70

File tree

6 files changed

+128
-0
lines changed

6 files changed

+128
-0
lines changed

instrumentation/aws-sdk/aws-sdk-1.11/library/build.gradle.kts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,12 +36,25 @@ if (!(findProperty("testLatestDeps") as Boolean)) {
3636
}
3737
}
3838

39+
testing {
40+
suites {
41+
val testSecretsManager by registering(JvmTestSuite::class) {
42+
dependencies {
43+
implementation(project())
44+
implementation(project(":instrumentation:aws-sdk:aws-sdk-1.11:testing"))
45+
implementation("com.amazonaws:aws-java-sdk-secretsmanager:1.12.80")
46+
}
47+
}
48+
}
49+
}
50+
3951
tasks {
4052
val testStableSemconv by registering(Test::class) {
4153
jvmArgs("-Dotel.semconv-stability.opt-in=database")
4254
}
4355

4456
check {
57+
dependsOn(testing.suites)
4558
dependsOn(testStableSemconv)
4659
}
4760
}

instrumentation/aws-sdk/aws-sdk-1.11/library/src/main/java/io/opentelemetry/instrumentation/awssdk/v1_11/AwsSdkAttributesExtractor.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ class AwsSdkAttributesExtractor implements AttributesExtractor<Request<?>, Respo
2424
private static final AttributeKey<String> AWS_REQUEST_ID = stringKey("aws.request_id");
2525

2626
// Copied from AwsIncubatingAttributes
27+
private static final AttributeKey<String> AWS_SECRETSMANAGER_SECRET_ARN =
28+
stringKey("aws.secretsmanager.secret.arn");
2729
private static final AttributeKey<String> AWS_STEP_FUNCTIONS_ACTIVITY_ARN =
2830
stringKey("aws.step_functions.activity.arn");
2931
private static final AttributeKey<String> AWS_STEP_FUNCTIONS_STATE_MACHINE_ARN =
@@ -43,6 +45,8 @@ private static boolean canGetResponseMetadata() {
4345
@Override
4446
public void onStart(AttributesBuilder attributes, Context parentContext, Request<?> request) {
4547
Object originalRequest = request.getOriginalRequest();
48+
setAttribute(
49+
attributes, AWS_SECRETSMANAGER_SECRET_ARN, originalRequest, RequestAccess::getSecretArn);
4650
setAttribute(
4751
attributes,
4852
AWS_STEP_FUNCTIONS_STATE_MACHINE_ARN,
@@ -64,6 +68,7 @@ public void onEnd(
6468
@Nullable Throwable error) {
6569
if (response != null) {
6670
Object awsResp = response.getAwsResponse();
71+
setAttribute(attributes, AWS_SECRETSMANAGER_SECRET_ARN, awsResp, RequestAccess::getSecretArn);
6772
setAttribute(
6873
attributes,
6974
AWS_STEP_FUNCTIONS_STATE_MACHINE_ARN,

instrumentation/aws-sdk/aws-sdk-1.11/library/src/main/java/io/opentelemetry/instrumentation/awssdk/v1_11/RequestAccess.java

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111
import javax.annotation.Nullable;
1212

1313
final class RequestAccess {
14+
private static final String SECRETS_MANAGER_REQUEST_CLASS_PREFIX =
15+
"com.amazonaws.services.secretsmanager.model.";
1416
private static final String STEP_FUNCTIONS_REQUEST_CLASS_PREFIX =
1517
"com.amazonaws.services.stepfunctions.model.";
1618

@@ -22,6 +24,15 @@ protected RequestAccess computeValue(Class<?> type) {
2224
}
2325
};
2426

27+
@Nullable
28+
static String getSecretArn(Object request) {
29+
if (request == null) {
30+
return null;
31+
}
32+
RequestAccess access = REQUEST_ACCESSORS.get(request.getClass());
33+
return invokeOrNull(access.getSecretArn, request);
34+
}
35+
2536
@Nullable
2637
static String getStepFunctionsActivityArn(Object request) {
2738
if (request == null) {
@@ -97,6 +108,7 @@ private static String invokeOrNull(@Nullable MethodHandle method, Object obj) {
97108
@Nullable private final MethodHandle getBucketName;
98109
@Nullable private final MethodHandle getQueueUrl;
99110
@Nullable private final MethodHandle getQueueName;
111+
@Nullable private final MethodHandle getSecretArn;
100112
@Nullable private final MethodHandle getStreamName;
101113
@Nullable private final MethodHandle getTableName;
102114
@Nullable private final MethodHandle getTopicArn;
@@ -112,6 +124,9 @@ private RequestAccess(Class<?> clz) {
112124
getTableName = findAccessorOrNull(clz, "getTableName");
113125
getTopicArn = findAccessorOrNull(clz, "getTopicArn");
114126
getTargetArn = findAccessorOrNull(clz, "getTargetArn");
127+
128+
boolean isSecretsManager = clz.getName().startsWith(SECRETS_MANAGER_REQUEST_CLASS_PREFIX);
129+
getSecretArn = isSecretsManager ? findAccessorOrNull(clz, "getARN") : null;
115130
boolean isStepFunction = clz.getName().startsWith(STEP_FUNCTIONS_REQUEST_CLASS_PREFIX);
116131
getStateMachineArn = isStepFunction ? findAccessorOrNull(clz, "getStateMachineArn") : null;
117132
getStepFunctionsActivityArn = isStepFunction ? findAccessorOrNull(clz, "getActivityArn") : null;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
/*
2+
* Copyright The OpenTelemetry Authors
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
package io.opentelemetry.instrumentation.awssdk.v1_11;
7+
8+
import com.amazonaws.services.secretsmanager.AWSSecretsManagerClientBuilder;
9+
import io.opentelemetry.instrumentation.testing.junit.InstrumentationExtension;
10+
import io.opentelemetry.instrumentation.testing.junit.LibraryInstrumentationExtension;
11+
import org.junit.jupiter.api.extension.RegisterExtension;
12+
13+
class SecretsManagerClientTest extends AbstractSecretsManagerClientTest {
14+
@RegisterExtension
15+
private static final InstrumentationExtension testing = LibraryInstrumentationExtension.create();
16+
17+
@Override
18+
protected InstrumentationExtension testing() {
19+
return testing;
20+
}
21+
22+
@Override
23+
public AWSSecretsManagerClientBuilder configureClient(
24+
AWSSecretsManagerClientBuilder clientBuilder) {
25+
26+
return clientBuilder.withRequestHandlers(
27+
AwsSdkTelemetry.builder(testing().getOpenTelemetry())
28+
.setCaptureExperimentalSpanAttributes(true)
29+
.build()
30+
.newRequestHandler());
31+
}
32+
}

instrumentation/aws-sdk/aws-sdk-1.11/testing/build.gradle.kts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ dependencies {
1212
compileOnly("com.amazonaws:aws-java-sdk-kinesis:1.11.106")
1313
compileOnly("com.amazonaws:aws-java-sdk-rds:1.11.106")
1414
compileOnly("com.amazonaws:aws-java-sdk-s3:1.11.106")
15+
compileOnly("com.amazonaws:aws-java-sdk-secretsmanager:1.12.80")
1516
compileOnly("com.amazonaws:aws-java-sdk-sns:1.11.106")
1617
compileOnly("com.amazonaws:aws-java-sdk-sqs:1.11.106")
1718
compileOnly("com.amazonaws:aws-java-sdk-stepfunctions:1.11.106")
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
/*
2+
* Copyright The OpenTelemetry Authors
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
package io.opentelemetry.instrumentation.awssdk.v1_11;
7+
8+
import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.equalTo;
9+
import static io.opentelemetry.semconv.incubating.AwsIncubatingAttributes.AWS_SECRETSMANAGER_SECRET_ARN;
10+
import static java.util.Collections.singletonList;
11+
12+
import com.amazonaws.services.secretsmanager.AWSSecretsManager;
13+
import com.amazonaws.services.secretsmanager.AWSSecretsManagerClientBuilder;
14+
import com.amazonaws.services.secretsmanager.model.CreateSecretRequest;
15+
import io.opentelemetry.sdk.testing.assertj.AttributeAssertion;
16+
import io.opentelemetry.testing.internal.armeria.common.HttpResponse;
17+
import io.opentelemetry.testing.internal.armeria.common.HttpStatus;
18+
import io.opentelemetry.testing.internal.armeria.common.MediaType;
19+
import java.util.List;
20+
import org.junit.jupiter.api.Test;
21+
22+
public abstract class AbstractSecretsManagerClientTest extends AbstractBaseAwsClientTest {
23+
24+
public abstract AWSSecretsManagerClientBuilder configureClient(
25+
AWSSecretsManagerClientBuilder client);
26+
27+
@Override
28+
protected boolean hasRequestId() {
29+
return false;
30+
}
31+
32+
@Test
33+
public void sendRequestWithMockedResponse() throws Exception {
34+
AWSSecretsManagerClientBuilder clientBuilder = AWSSecretsManagerClientBuilder.standard();
35+
AWSSecretsManager client =
36+
configureClient(clientBuilder)
37+
.withEndpointConfiguration(endpoint)
38+
.withCredentials(credentialsProvider)
39+
.build();
40+
41+
String body =
42+
"{"
43+
+ "\"ARN\": \"arn:aws:secretsmanager:us-west-2:123456789012:secret:MyTestDatabaseSecret-a1b2c3\","
44+
+ "\"Name\": \"MyTestDatabaseSecret\","
45+
+ "\"VersionId\": \"EXAMPLE1-90ab-cdef-fedc-ba987SECRET1\""
46+
+ "}";
47+
server.enqueue(HttpResponse.of(HttpStatus.OK, MediaType.PLAIN_TEXT_UTF_8, body));
48+
49+
Object response =
50+
client.createSecret(
51+
new CreateSecretRequest().withName("secretName").withSecretString("secretValue"));
52+
53+
List<AttributeAssertion> additionalAttributes =
54+
singletonList(
55+
equalTo(
56+
AWS_SECRETSMANAGER_SECRET_ARN,
57+
"arn:aws:secretsmanager:us-west-2:123456789012:secret:MyTestDatabaseSecret-a1b2c3"));
58+
59+
assertRequestWithMockedResponse(
60+
response, client, "AWSSecretsManager", "CreateSecret", "POST", additionalAttributes);
61+
}
62+
}

0 commit comments

Comments
 (0)