Skip to content

Commit d8cfd82

Browse files
committed
feat: AWS SDK v1 Step Functions auto-instrumentation support
This PR adds AWS SDK v1 auto-instrumentation support for the following AWS resource: Step Functions Tests Run: ./gradlew spotlessCheck ./gradlew clean assemble ./gradlew instrumentation:check ./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 d8cfd82

File tree

9 files changed

+211
-17
lines changed

9 files changed

+211
-17
lines changed

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

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,12 +41,13 @@ dependencies {
4141

4242
library("com.amazonaws:aws-java-sdk-core:1.11.0")
4343

44-
testLibrary("com.amazonaws:aws-java-sdk-s3:1.11.106")
45-
testLibrary("com.amazonaws:aws-java-sdk-rds:1.11.106")
44+
testLibrary("com.amazonaws:aws-java-sdk-dynamodb:1.11.106")
4645
testLibrary("com.amazonaws:aws-java-sdk-ec2:1.11.106")
4746
testLibrary("com.amazonaws:aws-java-sdk-kinesis:1.11.106")
48-
testLibrary("com.amazonaws:aws-java-sdk-dynamodb:1.11.106")
47+
testLibrary("com.amazonaws:aws-java-sdk-rds:1.11.106")
48+
testLibrary("com.amazonaws:aws-java-sdk-s3: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")
5051

5152
testImplementation(project(":instrumentation:aws-sdk:aws-sdk-1.11:testing"))
5253

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: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,13 @@ dependencies {
1111

1212
testImplementation(project(":instrumentation:aws-sdk:aws-sdk-1.11:testing"))
1313

14-
testLibrary("com.amazonaws:aws-java-sdk-s3:1.11.106")
15-
testLibrary("com.amazonaws:aws-java-sdk-rds:1.11.106")
14+
testLibrary("com.amazonaws:aws-java-sdk-dynamodb:1.11.106")
1615
testLibrary("com.amazonaws:aws-java-sdk-ec2:1.11.106")
1716
testLibrary("com.amazonaws:aws-java-sdk-kinesis:1.11.106")
18-
testLibrary("com.amazonaws:aws-java-sdk-dynamodb:1.11.106")
17+
testLibrary("com.amazonaws:aws-java-sdk-rds:1.11.106")
18+
testLibrary("com.amazonaws:aws-java-sdk-s3: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")
2021

2122
// last version that does not use json protocol
2223
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: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,10 @@ 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");
1923

2024
private AwsExperimentalAttributes() {}
2125
}

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

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99
import static io.opentelemetry.instrumentation.awssdk.v1_11.AwsExperimentalAttributes.AWS_BUCKET_NAME;
1010
import static io.opentelemetry.instrumentation.awssdk.v1_11.AwsExperimentalAttributes.AWS_QUEUE_NAME;
1111
import static io.opentelemetry.instrumentation.awssdk.v1_11.AwsExperimentalAttributes.AWS_QUEUE_URL;
12+
import static io.opentelemetry.instrumentation.awssdk.v1_11.AwsExperimentalAttributes.AWS_STATE_MACHINE_ARN;
13+
import static io.opentelemetry.instrumentation.awssdk.v1_11.AwsExperimentalAttributes.AWS_STEP_FUNCTIONS_ACTIVITY_ARN;
1214
import static io.opentelemetry.instrumentation.awssdk.v1_11.AwsExperimentalAttributes.AWS_STREAM_NAME;
1315
import static io.opentelemetry.instrumentation.awssdk.v1_11.AwsExperimentalAttributes.AWS_TABLE_NAME;
1416

@@ -35,6 +37,13 @@ public void onStart(AttributesBuilder attributes, Context parentContext, Request
3537
setRequestAttribute(attributes, AWS_QUEUE_NAME, originalRequest, RequestAccess::getQueueName);
3638
setRequestAttribute(attributes, AWS_STREAM_NAME, originalRequest, RequestAccess::getStreamName);
3739
setRequestAttribute(attributes, AWS_TABLE_NAME, originalRequest, RequestAccess::getTableName);
40+
setRequestAttribute(
41+
attributes, AWS_STATE_MACHINE_ARN, originalRequest, RequestAccess::getStateMachineArn);
42+
setRequestAttribute(
43+
attributes,
44+
AWS_STEP_FUNCTIONS_ACTIVITY_ARN,
45+
originalRequest,
46+
RequestAccess::getStepFunctionsActivityArn);
3847
}
3948

4049
private static void setRequestAttribute(
@@ -54,5 +63,16 @@ public void onEnd(
5463
Context context,
5564
Request<?> request,
5665
@Nullable Response<?> response,
57-
@Nullable Throwable error) {}
66+
@Nullable Throwable error) {
67+
if (response != null) {
68+
Object awsResp = response.getAwsResponse();
69+
setRequestAttribute(
70+
attributes, AWS_STATE_MACHINE_ARN, awsResp, RequestAccess::getStateMachineArn);
71+
setRequestAttribute(
72+
attributes,
73+
AWS_STEP_FUNCTIONS_ACTIVITY_ARN,
74+
awsResp,
75+
RequestAccess::getStepFunctionsActivityArn);
76+
}
77+
}
5878
}

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

Lines changed: 37 additions & 7 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 STEP_FUNCTIONS_REQUEST_CLASS_PREFIX =
15+
"com.amazonaws.services.stepfunctions.model.";
1416

1517
private static final ClassValue<RequestAccess> REQUEST_ACCESSORS =
1618
new ClassValue<RequestAccess>() {
@@ -20,6 +22,24 @@ protected RequestAccess computeValue(Class<?> type) {
2022
}
2123
};
2224

25+
@Nullable
26+
static String getStepFunctionsActivityArn(Object request) {
27+
if (request == null) {
28+
return null;
29+
}
30+
RequestAccess access = REQUEST_ACCESSORS.get(request.getClass());
31+
return invokeOrNull(access.getStepFunctionsActivityArn, request);
32+
}
33+
34+
@Nullable
35+
static String getStateMachineArn(Object request) {
36+
if (request == null) {
37+
return null;
38+
}
39+
RequestAccess access = REQUEST_ACCESSORS.get(request.getClass());
40+
return invokeOrNull(access.getStateMachineArn, request);
41+
}
42+
2343
@Nullable
2444
static String getBucketName(Object request) {
2545
RequestAccess access = REQUEST_ACCESSORS.get(request.getClass());
@@ -74,22 +94,32 @@ private static String invokeOrNull(@Nullable MethodHandle method, Object obj) {
7494
}
7595
}
7696

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;
97+
@Nullable private MethodHandle getBucketName;
98+
@Nullable private MethodHandle getQueueUrl;
99+
@Nullable private MethodHandle getQueueName;
100+
@Nullable private MethodHandle getStateMachineArn;
101+
@Nullable private MethodHandle getStepFunctionsActivityArn;
102+
@Nullable private MethodHandle getStreamName;
103+
@Nullable private MethodHandle getTableName;
104+
@Nullable private MethodHandle getTopicArn;
105+
@Nullable private MethodHandle getTargetArn;
84106

85107
private RequestAccess(Class<?> clz) {
108+
if (clz == null) {
109+
return;
110+
}
86111
getBucketName = findAccessorOrNull(clz, "getBucketName");
87112
getQueueUrl = findAccessorOrNull(clz, "getQueueUrl");
88113
getQueueName = findAccessorOrNull(clz, "getQueueName");
89114
getStreamName = findAccessorOrNull(clz, "getStreamName");
90115
getTableName = findAccessorOrNull(clz, "getTableName");
91116
getTopicArn = findAccessorOrNull(clz, "getTopicArn");
92117
getTargetArn = findAccessorOrNull(clz, "getTargetArn");
118+
String className = clz.getName();
119+
if (className.startsWith(STEP_FUNCTIONS_REQUEST_CLASS_PREFIX)) {
120+
getStateMachineArn = findAccessorOrNull(clz, "getStateMachineArn");
121+
getStepFunctionsActivityArn = findAccessorOrNull(clz, "getActivityArn");
122+
}
93123
}
94124

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

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

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,14 @@ dependencies {
77

88
api("com.amazonaws:aws-java-sdk-core:1.11.0")
99

10-
compileOnly("com.amazonaws:aws-java-sdk-s3:1.11.106")
11-
compileOnly("com.amazonaws:aws-java-sdk-rds:1.11.106")
10+
compileOnly("com.amazonaws:aws-java-sdk-dynamodb:1.11.106")
1211
compileOnly("com.amazonaws:aws-java-sdk-ec2:1.11.106")
1312
compileOnly("com.amazonaws:aws-java-sdk-kinesis:1.11.106")
14-
compileOnly("com.amazonaws:aws-java-sdk-dynamodb:1.11.106")
13+
compileOnly("com.amazonaws:aws-java-sdk-rds:1.11.106")
14+
compileOnly("com.amazonaws:aws-java-sdk-s3:1.11.106")
1515
compileOnly("com.amazonaws:aws-java-sdk-sns:1.11.106")
1616
compileOnly("com.amazonaws:aws-java-sdk-sqs:1.11.106")
17+
compileOnly("com.amazonaws:aws-java-sdk-stepfunctions:1.11.106")
1718

1819
// needed for SQS - using emq directly as localstack references emq v0.15.7 ie WITHOUT AWS trace header propagation
1920
implementation("org.elasticmq:elasticmq-rest-sqs_2.13")
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
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.api.common.AttributeKey.stringKey;
9+
import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.equalTo;
10+
import static java.util.Collections.singletonList;
11+
12+
import com.amazonaws.services.stepfunctions.AWSStepFunctions;
13+
import com.amazonaws.services.stepfunctions.AWSStepFunctionsClientBuilder;
14+
import com.amazonaws.services.stepfunctions.model.DescribeActivityRequest;
15+
import com.amazonaws.services.stepfunctions.model.DescribeStateMachineRequest;
16+
import io.opentelemetry.sdk.testing.assertj.AttributeAssertion;
17+
import io.opentelemetry.testing.internal.armeria.common.HttpResponse;
18+
import io.opentelemetry.testing.internal.armeria.common.HttpStatus;
19+
import io.opentelemetry.testing.internal.armeria.common.MediaType;
20+
import java.util.List;
21+
import java.util.function.Function;
22+
import java.util.stream.Stream;
23+
import org.junit.jupiter.params.ParameterizedTest;
24+
import org.junit.jupiter.params.provider.Arguments;
25+
import org.junit.jupiter.params.provider.MethodSource;
26+
27+
public abstract class AbstractStepFunctionsClientTest extends AbstractBaseAwsClientTest {
28+
29+
public abstract AWSStepFunctionsClientBuilder configureClient(
30+
AWSStepFunctionsClientBuilder client);
31+
32+
@Override
33+
protected boolean hasRequestId() {
34+
return false;
35+
}
36+
37+
@ParameterizedTest
38+
@MethodSource("provideArguments")
39+
public void testSendRequestWithMockedResponse(
40+
String operation,
41+
List<AttributeAssertion> additionalAttributes,
42+
Function<AWSStepFunctions, Object> call)
43+
throws Exception {
44+
45+
AWSStepFunctionsClientBuilder clientBuilder = AWSStepFunctionsClientBuilder.standard();
46+
47+
AWSStepFunctions client =
48+
configureClient(clientBuilder)
49+
.withEndpointConfiguration(endpoint)
50+
.withCredentials(credentialsProvider)
51+
.build();
52+
53+
server.enqueue(HttpResponse.of(HttpStatus.OK, MediaType.PLAIN_TEXT_UTF_8, ""));
54+
55+
Object response = call.apply(client);
56+
assertRequestWithMockedResponse(
57+
response, client, "AWSStepFunctions", operation, "POST", additionalAttributes);
58+
}
59+
60+
private static Stream<Arguments> provideArguments() {
61+
return Stream.of(
62+
Arguments.of(
63+
"DescribeStateMachine",
64+
singletonList(
65+
equalTo(stringKey("aws.stepfunctions.state_machine.arn"), "stateMachineArn")),
66+
(Function<AWSStepFunctions, Object>)
67+
c ->
68+
c.describeStateMachine(
69+
new DescribeStateMachineRequest().withStateMachineArn("stateMachineArn"))),
70+
Arguments.of(
71+
"DescribeActivity",
72+
singletonList(equalTo(stringKey("aws.stepfunctions.activity.arn"), "activityArn")),
73+
(Function<AWSStepFunctions, Object>)
74+
c ->
75+
c.describeActivity(
76+
new DescribeActivityRequest().withActivityArn("activityArn"))));
77+
}
78+
}

0 commit comments

Comments
 (0)