Skip to content

Commit 01b526f

Browse files
committed
feat: Add auto-instrumentation support for AWS resources in AWS SDK v1
This PR adds auto-instrumentation support for the following AWS resources: Lambda Secrets Manager SNS Step Functions Tests Run: ./gradlew spotlessCheck ./gradlew clean assemble ./gradlew instrumentation:test ./gradlew :smoke-tests:test No regression issues found. All newly added tests pass. Backward Compatibility: There is no risk of breaking existing functionality. This change only adds instrumentation for additional AWS resources without modifying the existing behavior of the auto-instrumentation library.
1 parent 5357d88 commit 01b526f

File tree

16 files changed

+525
-30
lines changed

16 files changed

+525
-30
lines changed

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,8 @@ dependencies {
4747
testLibrary("com.amazonaws:aws-java-sdk-kinesis:1.11.106")
4848
testLibrary("com.amazonaws:aws-java-sdk-dynamodb:1.11.106")
4949
testLibrary("com.amazonaws:aws-java-sdk-sns:1.11.106")
50+
testLibrary("com.amazonaws:aws-java-sdk-stepfunctions:1.11.106")
51+
testLibrary("com.amazonaws:aws-java-sdk-lambda:1.11.106")
5052

5153
testImplementation(project(":instrumentation:aws-sdk:aws-sdk-1.11:testing"))
5254

instrumentation/aws-sdk/aws-sdk-1.11/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/awssdk/v1_11/AwsSpanAssertions.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@ static SpanDataAssert sns(SpanDataAssert span, String topicArn, String rpcMethod
9090
.hasAttributesSatisfyingExactly(
9191
equalTo(stringKey("aws.agent"), "java-aws-sdk"),
9292
equalTo(MESSAGING_DESTINATION_NAME, topicArn),
93+
satisfies(stringKey("aws.sns.topic.arn"), v -> v.isInstanceOf(String.class)),
9394
satisfies(AWS_REQUEST_ID, v -> v.isInstanceOf(String.class)),
9495
equalTo(RPC_METHOD, rpcMethod),
9596
equalTo(RPC_SYSTEM, "aws-api"),
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
/*
2+
* Copyright The OpenTelemetry Authors
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
package io.opentelemetry.javaagent.instrumentation.awssdk.v1_11;
7+
8+
import com.amazonaws.services.lambda.AWSLambdaClientBuilder;
9+
import io.opentelemetry.instrumentation.awssdk.v1_11.AbstractLambdaClientTest;
10+
import io.opentelemetry.instrumentation.testing.junit.AgentInstrumentationExtension;
11+
import io.opentelemetry.instrumentation.testing.junit.InstrumentationExtension;
12+
import org.junit.jupiter.api.extension.RegisterExtension;
13+
14+
class LambdaClientTest extends AbstractLambdaClientTest {
15+
@RegisterExtension
16+
static final InstrumentationExtension testing = AgentInstrumentationExtension.create();
17+
18+
@Override
19+
protected InstrumentationExtension testing() {
20+
return testing;
21+
}
22+
23+
@Override
24+
public AWSLambdaClientBuilder configureClient(AWSLambdaClientBuilder clientBuilder) {
25+
return clientBuilder;
26+
}
27+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
/*
2+
* Copyright The OpenTelemetry Authors
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
package io.opentelemetry.javaagent.instrumentation.awssdk.v1_11;
7+
8+
import com.amazonaws.services.stepfunctions.AWSStepFunctionsClientBuilder;
9+
import io.opentelemetry.instrumentation.awssdk.v1_11.AbstractStepFunctionsClientTest;
10+
import io.opentelemetry.instrumentation.testing.junit.AgentInstrumentationExtension;
11+
import io.opentelemetry.instrumentation.testing.junit.InstrumentationExtension;
12+
import org.junit.jupiter.api.extension.RegisterExtension;
13+
14+
class StepFunctionsClientTest extends AbstractStepFunctionsClientTest {
15+
@RegisterExtension
16+
static final InstrumentationExtension testing = AgentInstrumentationExtension.create();
17+
18+
@Override
19+
protected InstrumentationExtension testing() {
20+
return testing;
21+
}
22+
23+
@Override
24+
public AWSStepFunctionsClientBuilder configureClient(
25+
AWSStepFunctionsClientBuilder clientBuilder) {
26+
return clientBuilder;
27+
}
28+
}

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,11 @@ dependencies {
1717
testLibrary("com.amazonaws:aws-java-sdk-kinesis:1.11.106")
1818
testLibrary("com.amazonaws:aws-java-sdk-dynamodb:1.11.106")
1919
testLibrary("com.amazonaws:aws-java-sdk-sns:1.11.106")
20+
testLibrary("com.amazonaws:aws-java-sdk-stepfunctions:1.11.106")
21+
testLibrary("com.amazonaws:aws-java-sdk-lambda:1.11.106")
22+
23+
// Tests on the MacBook indicate that this keeps the core at version 1.11.0.
24+
testLibrary("com.amazonaws:aws-java-sdk-secretsmanager:1.11.309")
2025

2126
// last version that does not use json protocol
2227
latestDepTestLibrary("com.amazonaws:aws-java-sdk-sqs:1.12.583") // documented limitation

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

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,15 @@ final class AwsExperimentalAttributes {
1616
static final AttributeKey<String> AWS_QUEUE_NAME = stringKey("aws.queue.name");
1717
static final AttributeKey<String> AWS_STREAM_NAME = stringKey("aws.stream.name");
1818
static final AttributeKey<String> AWS_TABLE_NAME = stringKey("aws.table.name");
19+
static final AttributeKey<String> AWS_STATE_MACHINE_ARN =
20+
stringKey("aws.stepfunctions.state_machine.arn");
21+
static final AttributeKey<String> AWS_STEP_FUNCTIONS_ACTIVITY_ARN =
22+
stringKey("aws.stepfunctions.activity.arn");
23+
static final AttributeKey<String> AWS_SNS_TOPIC_ARN = stringKey("aws.sns.topic.arn");
24+
static final AttributeKey<String> AWS_SECRET_ARN = stringKey("aws.secretsmanager.secret.arn");
25+
static final AttributeKey<String> AWS_LAMBDA_NAME = stringKey("aws.lambda.function.name");
26+
static final AttributeKey<String> AWS_LAMBDA_RESOURCE_ID =
27+
stringKey("aws.lambda.resource_mapping.id");
1928

2029
private AwsExperimentalAttributes() {}
2130
}

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

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,14 @@
77

88
import static io.opentelemetry.instrumentation.awssdk.v1_11.AwsExperimentalAttributes.AWS_AGENT;
99
import static io.opentelemetry.instrumentation.awssdk.v1_11.AwsExperimentalAttributes.AWS_BUCKET_NAME;
10+
import static io.opentelemetry.instrumentation.awssdk.v1_11.AwsExperimentalAttributes.AWS_LAMBDA_NAME;
11+
import static io.opentelemetry.instrumentation.awssdk.v1_11.AwsExperimentalAttributes.AWS_LAMBDA_RESOURCE_ID;
1012
import static io.opentelemetry.instrumentation.awssdk.v1_11.AwsExperimentalAttributes.AWS_QUEUE_NAME;
1113
import static io.opentelemetry.instrumentation.awssdk.v1_11.AwsExperimentalAttributes.AWS_QUEUE_URL;
14+
import static io.opentelemetry.instrumentation.awssdk.v1_11.AwsExperimentalAttributes.AWS_SECRET_ARN;
15+
import static io.opentelemetry.instrumentation.awssdk.v1_11.AwsExperimentalAttributes.AWS_SNS_TOPIC_ARN;
16+
import static io.opentelemetry.instrumentation.awssdk.v1_11.AwsExperimentalAttributes.AWS_STATE_MACHINE_ARN;
17+
import static io.opentelemetry.instrumentation.awssdk.v1_11.AwsExperimentalAttributes.AWS_STEP_FUNCTIONS_ACTIVITY_ARN;
1218
import static io.opentelemetry.instrumentation.awssdk.v1_11.AwsExperimentalAttributes.AWS_STREAM_NAME;
1319
import static io.opentelemetry.instrumentation.awssdk.v1_11.AwsExperimentalAttributes.AWS_TABLE_NAME;
1420

@@ -35,6 +41,18 @@ public void onStart(AttributesBuilder attributes, Context parentContext, Request
3541
setRequestAttribute(attributes, AWS_QUEUE_NAME, originalRequest, RequestAccess::getQueueName);
3642
setRequestAttribute(attributes, AWS_STREAM_NAME, originalRequest, RequestAccess::getStreamName);
3743
setRequestAttribute(attributes, AWS_TABLE_NAME, originalRequest, RequestAccess::getTableName);
44+
setRequestAttribute(
45+
attributes, AWS_STATE_MACHINE_ARN, originalRequest, RequestAccess::getStateMachineArn);
46+
setRequestAttribute(
47+
attributes,
48+
AWS_STEP_FUNCTIONS_ACTIVITY_ARN,
49+
originalRequest,
50+
RequestAccess::getStepFunctionsActivityArn);
51+
setRequestAttribute(attributes, AWS_SNS_TOPIC_ARN, originalRequest, RequestAccess::getTopicArn);
52+
setRequestAttribute(attributes, AWS_SECRET_ARN, originalRequest, RequestAccess::getSecretArn);
53+
setRequestAttribute(attributes, AWS_LAMBDA_NAME, originalRequest, RequestAccess::getLambdaName);
54+
setRequestAttribute(
55+
attributes, AWS_LAMBDA_RESOURCE_ID, originalRequest, RequestAccess::getLambdaResourceId);
3856
}
3957

4058
private static void setRequestAttribute(
@@ -54,5 +72,18 @@ public void onEnd(
5472
Context context,
5573
Request<?> request,
5674
@Nullable Response<?> response,
57-
@Nullable Throwable error) {}
75+
@Nullable Throwable error) {
76+
if (response != null) {
77+
Object awsResp = response.getAwsResponse();
78+
setRequestAttribute(
79+
attributes, AWS_STATE_MACHINE_ARN, awsResp, RequestAccess::getStateMachineArn);
80+
setRequestAttribute(
81+
attributes,
82+
AWS_STEP_FUNCTIONS_ACTIVITY_ARN,
83+
awsResp,
84+
RequestAccess::getStepFunctionsActivityArn);
85+
setRequestAttribute(attributes, AWS_SNS_TOPIC_ARN, awsResp, RequestAccess::getTopicArn);
86+
setRequestAttribute(attributes, AWS_SECRET_ARN, awsResp, RequestAccess::getSecretArn);
87+
}
88+
}
5889
}

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

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

1313
final class RequestAccess {
14+
private static final String LAMBDA_REQUEST_CLASS_PREFIX = "com.amazonaws.services.lambda.model.";
15+
private static final String SECRETS_MANAGER_REQUEST_CLASS_PREFIX =
16+
"com.amazonaws.services.secretsmanager.model.";
1417

1518
private static final ClassValue<RequestAccess> REQUEST_ACCESSORS =
1619
new ClassValue<RequestAccess>() {
@@ -20,6 +23,51 @@ protected RequestAccess computeValue(Class<?> type) {
2023
}
2124
};
2225

26+
@Nullable
27+
static String getLambdaName(Object request) {
28+
if (request == null) {
29+
return null;
30+
}
31+
RequestAccess access = REQUEST_ACCESSORS.get(request.getClass());
32+
return invokeOrNull(access.getLambdaName, request);
33+
}
34+
35+
@Nullable
36+
static String getLambdaResourceId(Object request) {
37+
if (request == null) {
38+
return null;
39+
}
40+
RequestAccess access = REQUEST_ACCESSORS.get(request.getClass());
41+
return invokeOrNull(access.getLambdaResourceId, request);
42+
}
43+
44+
@Nullable
45+
static String getSecretArn(Object request) {
46+
if (request == null) {
47+
return null;
48+
}
49+
RequestAccess access = REQUEST_ACCESSORS.get(request.getClass());
50+
return invokeOrNull(access.getSecretArn, request);
51+
}
52+
53+
@Nullable
54+
static String getStepFunctionsActivityArn(Object request) {
55+
if (request == null) {
56+
return null;
57+
}
58+
RequestAccess access = REQUEST_ACCESSORS.get(request.getClass());
59+
return invokeOrNull(access.getStepFunctionsActivityArn, request);
60+
}
61+
62+
@Nullable
63+
static String getStateMachineArn(Object request) {
64+
if (request == null) {
65+
return null;
66+
}
67+
RequestAccess access = REQUEST_ACCESSORS.get(request.getClass());
68+
return invokeOrNull(access.getStateMachineArn, request);
69+
}
70+
2371
@Nullable
2472
static String getBucketName(Object request) {
2573
RequestAccess access = REQUEST_ACCESSORS.get(request.getClass());
@@ -52,6 +100,9 @@ static String getTableName(Object request) {
52100

53101
@Nullable
54102
static String getTopicArn(Object request) {
103+
if (request == null) {
104+
return null;
105+
}
55106
RequestAccess access = REQUEST_ACCESSORS.get(request.getClass());
56107
return invokeOrNull(access.getTopicArn, request);
57108
}
@@ -74,22 +125,40 @@ private static String invokeOrNull(@Nullable MethodHandle method, Object obj) {
74125
}
75126
}
76127

77-
@Nullable private final MethodHandle getBucketName;
78-
@Nullable private final MethodHandle getQueueUrl;
79-
@Nullable private final MethodHandle getQueueName;
80-
@Nullable private final MethodHandle getStreamName;
81-
@Nullable private final MethodHandle getTableName;
82-
@Nullable private final MethodHandle getTopicArn;
83-
@Nullable private final MethodHandle getTargetArn;
128+
@Nullable private MethodHandle getBucketName;
129+
@Nullable private MethodHandle getQueueUrl;
130+
@Nullable private MethodHandle getQueueName;
131+
@Nullable private MethodHandle getStreamName;
132+
@Nullable private MethodHandle getTableName;
133+
@Nullable private MethodHandle getTopicArn;
134+
@Nullable private MethodHandle getTargetArn;
135+
@Nullable private MethodHandle getStateMachineArn;
136+
@Nullable private MethodHandle getStepFunctionsActivityArn;
137+
@Nullable private MethodHandle getSecretArn;
138+
@Nullable private MethodHandle getLambdaName;
139+
@Nullable private MethodHandle getLambdaResourceId;
84140

85141
private RequestAccess(Class<?> clz) {
142+
if (clz == null) {
143+
return;
144+
}
86145
getBucketName = findAccessorOrNull(clz, "getBucketName");
87146
getQueueUrl = findAccessorOrNull(clz, "getQueueUrl");
88147
getQueueName = findAccessorOrNull(clz, "getQueueName");
89148
getStreamName = findAccessorOrNull(clz, "getStreamName");
90149
getTableName = findAccessorOrNull(clz, "getTableName");
91150
getTopicArn = findAccessorOrNull(clz, "getTopicArn");
92151
getTargetArn = findAccessorOrNull(clz, "getTargetArn");
152+
getStateMachineArn = findAccessorOrNull(clz, "getStateMachineArn");
153+
getStepFunctionsActivityArn = findAccessorOrNull(clz, "getActivityArn");
154+
String className = clz.getName();
155+
if (className.startsWith(SECRETS_MANAGER_REQUEST_CLASS_PREFIX)) {
156+
getSecretArn = findAccessorOrNull(clz, "getARN");
157+
}
158+
if (className.startsWith(LAMBDA_REQUEST_CLASS_PREFIX)) {
159+
getLambdaName = findAccessorOrNull(clz, "getFunctionName");
160+
getLambdaResourceId = findAccessorOrNull(clz, "getUUID");
161+
}
93162
}
94163

95164
@Nullable
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
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.lambda.AWSLambdaClientBuilder;
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 LambdaClientTest extends AbstractLambdaClientTest {
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 AWSLambdaClientBuilder configureClient(AWSLambdaClientBuilder clientBuilder) {
24+
return clientBuilder.withRequestHandlers(
25+
AwsSdkTelemetry.builder(testing().getOpenTelemetry())
26+
.setCaptureExperimentalSpanAttributes(true)
27+
.build()
28+
.newRequestHandler());
29+
}
30+
}
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+
}

0 commit comments

Comments
 (0)