Skip to content

Commit 64f0131

Browse files
committed
feat: Add AWS_SNS_TOPIC_ARN semantic convention support for AWS SNS SDK
This PR adds the AWS_SNS_TOPIC_ARN semantic convention attribute for the following AWS resources: AWS SNS SDK v1 AWS SNS SDK v2 The topic ARN is extracted from both request and response objects, and this behavior is covered by unit tests. Tests Run: ./gradlew spotlessCheck ./gradlew instrumentation:check ./gradlew :smoke-tests:test All newly added tests pass, and no regressions were found. Backward Compatibility: This change is fully backward compatible. It introduces instrumentation for an additional AWS resource without modifying existing behavior in the auto-instrumentation library.
1 parent c3e9e59 commit 64f0131

File tree

7 files changed

+195
-76
lines changed

7 files changed

+195
-76
lines changed

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
import static io.opentelemetry.semconv.ServerAttributes.SERVER_PORT;
1616
import static io.opentelemetry.semconv.UrlAttributes.URL_FULL;
1717
import static io.opentelemetry.semconv.incubating.AwsIncubatingAttributes.AWS_REQUEST_ID;
18+
import static io.opentelemetry.semconv.incubating.AwsIncubatingAttributes.AWS_SNS_TOPIC_ARN;
1819
import static io.opentelemetry.semconv.incubating.MessagingIncubatingAttributes.MESSAGING_DESTINATION_NAME;
1920
import static io.opentelemetry.semconv.incubating.RpcIncubatingAttributes.RPC_METHOD;
2021
import static io.opentelemetry.semconv.incubating.RpcIncubatingAttributes.RPC_SERVICE;
@@ -90,6 +91,7 @@ static SpanDataAssert sns(SpanDataAssert span, String topicArn, String rpcMethod
9091
.hasAttributesSatisfyingExactly(
9192
equalTo(stringKey("aws.agent"), "java-aws-sdk"),
9293
equalTo(MESSAGING_DESTINATION_NAME, topicArn),
94+
satisfies(AWS_SNS_TOPIC_ARN, v -> v.isInstanceOf(String.class)),
9395
satisfies(AWS_REQUEST_ID, v -> v.isInstanceOf(String.class)),
9496
equalTo(RPC_METHOD, rpcMethod),
9597
equalTo(RPC_SYSTEM, "aws-api"),

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

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ 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_SNS_TOPIC_ARN = stringKey("aws.sns.topic.arn");
2728
private static final AttributeKey<String> AWS_STEP_FUNCTIONS_ACTIVITY_ARN =
2829
stringKey("aws.step_functions.activity.arn");
2930
private static final AttributeKey<String> AWS_STEP_FUNCTIONS_STATE_MACHINE_ARN =
@@ -43,6 +44,7 @@ private static boolean canGetResponseMetadata() {
4344
@Override
4445
public void onStart(AttributesBuilder attributes, Context parentContext, Request<?> request) {
4546
Object originalRequest = request.getOriginalRequest();
47+
setAttribute(attributes, AWS_SNS_TOPIC_ARN, originalRequest, RequestAccess::getSnsTopicArn);
4648
setAttribute(
4749
attributes,
4850
AWS_STEP_FUNCTIONS_STATE_MACHINE_ARN,
@@ -62,8 +64,9 @@ public void onEnd(
6264
Request<?> request,
6365
@Nullable Response<?> response,
6466
@Nullable Throwable error) {
65-
if (response != null) {
66-
Object awsResp = response.getAwsResponse();
67+
Object awsResp = getAwsResponse(response);
68+
if (awsResp != null) {
69+
setAttribute(attributes, AWS_SNS_TOPIC_ARN, awsResp, RequestAccess::getSnsTopicArn);
6770
setAttribute(
6871
attributes,
6972
AWS_STEP_FUNCTIONS_STATE_MACHINE_ARN,
@@ -106,4 +109,11 @@ public static void setAttribute(
106109
attributes.put(key, value);
107110
}
108111
}
112+
113+
private static Object getAwsResponse(Response<?> response) {
114+
if (response == null) {
115+
return null;
116+
}
117+
return response.getAwsResponse();
118+
}
109119
}

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

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,10 @@ static String getTableName(Object request) {
7171
}
7272

7373
@Nullable
74-
static String getTopicArn(Object request) {
74+
static String getSnsTopicArn(Object request) {
75+
if (request == null) {
76+
return null;
77+
}
7578
RequestAccess access = REQUEST_ACCESSORS.get(request.getClass());
7679
return invokeOrNull(access.getTopicArn, request);
7780
}

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ public void onStart(AttributesBuilder attributes, Context parentContext, Request
3232
* falling back to the target ARN. If neither is found null is returned.
3333
*/
3434
private static String findMessageDestination(AmazonWebServiceRequest request) {
35-
String destination = RequestAccess.getTopicArn(request);
35+
String destination = RequestAccess.getSnsTopicArn(request);
3636
if (destination != null) {
3737
return destination;
3838
}

instrumentation/aws-sdk/aws-sdk-1.11/testing/src/main/java/io/opentelemetry/instrumentation/awssdk/v1_11/AbstractSnsClientTest.java

Lines changed: 69 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -6,24 +6,42 @@
66
package io.opentelemetry.instrumentation.awssdk.v1_11;
77

88
import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.equalTo;
9+
import static io.opentelemetry.semconv.incubating.AwsIncubatingAttributes.AWS_SNS_TOPIC_ARN;
910
import static io.opentelemetry.semconv.incubating.MessagingIncubatingAttributes.MESSAGING_DESTINATION_NAME;
11+
import static java.util.Arrays.asList;
1012
import static java.util.Collections.singletonList;
1113

1214
import com.amazonaws.services.sns.AmazonSNS;
1315
import com.amazonaws.services.sns.AmazonSNSClientBuilder;
16+
import com.amazonaws.services.sns.model.CreateTopicRequest;
1417
import com.amazonaws.services.sns.model.PublishRequest;
1518
import io.opentelemetry.sdk.testing.assertj.AttributeAssertion;
1619
import io.opentelemetry.testing.internal.armeria.common.HttpResponse;
1720
import io.opentelemetry.testing.internal.armeria.common.HttpStatus;
1821
import io.opentelemetry.testing.internal.armeria.common.MediaType;
1922
import java.util.List;
20-
import java.util.function.Function;
21-
import java.util.stream.Stream;
22-
import org.junit.jupiter.params.ParameterizedTest;
23-
import org.junit.jupiter.params.provider.Arguments;
24-
import org.junit.jupiter.params.provider.MethodSource;
23+
import org.junit.jupiter.api.Test;
2524

2625
public abstract class AbstractSnsClientTest extends AbstractBaseAwsClientTest {
26+
private static final String publishResponseBody =
27+
"<PublishResponse xmlns=\"https://sns.amazonaws.com/doc/2010-03-31/\">"
28+
+ " <PublishResult>"
29+
+ " <MessageId>567910cd-659e-55d4-8ccb-5aaf14679dc0</MessageId>"
30+
+ " </PublishResult>"
31+
+ " <ResponseMetadata>"
32+
+ " <RequestId>d74b8436-ae13-5ab4-a9ff-ce54dfea72a0</RequestId>"
33+
+ " </ResponseMetadata>"
34+
+ "</PublishResponse>";
35+
36+
private static final String createTopicResponseBody =
37+
"<CreateTopicResponse xmlns=\"https://sns.amazonaws.com/doc/2010-03-31/\">"
38+
+ " <CreateTopicResult>"
39+
+ " <TopicArn>arn:aws:sns:us-east-1:123456789012:sns-topic-foo</TopicArn>"
40+
+ " </CreateTopicResult>"
41+
+ " <ResponseMetadata>"
42+
+ " <RequestId>d74b8436-ae13-5ab4-a9ff-ce54dfea72a0</RequestId>"
43+
+ " </ResponseMetadata>"
44+
+ "</CreateTopicResponse>";
2745

2846
public abstract AmazonSNSClientBuilder configureClient(AmazonSNSClientBuilder client);
2947

@@ -32,47 +50,66 @@ protected boolean hasRequestId() {
3250
return true;
3351
}
3452

35-
@ParameterizedTest
36-
@MethodSource("provideArguments")
37-
public void testSendRequestWithMockedResponse(Function<AmazonSNS, Object> call) throws Exception {
53+
@Test
54+
public void testPublishRequestWithTargetArnAndMockedResponse() throws Exception {
3855
AmazonSNSClientBuilder clientBuilder = AmazonSNSClientBuilder.standard();
3956
AmazonSNS client =
4057
configureClient(clientBuilder)
4158
.withEndpointConfiguration(endpoint)
4259
.withCredentials(credentialsProvider)
4360
.build();
4461

45-
String body =
46-
"<PublishResponse xmlns=\"https://sns.amazonaws.com/doc/2010-03-31/\">"
47-
+ " <PublishResult>"
48-
+ " <MessageId>567910cd-659e-55d4-8ccb-5aaf14679dc0</MessageId>"
49-
+ " </PublishResult>"
50-
+ " <ResponseMetadata>"
51-
+ " <RequestId>d74b8436-ae13-5ab4-a9ff-ce54dfea72a0</RequestId>"
52-
+ " </ResponseMetadata>"
53-
+ "</PublishResponse>";
62+
server.enqueue(HttpResponse.of(HttpStatus.OK, MediaType.PLAIN_TEXT_UTF_8, publishResponseBody));
63+
List<AttributeAssertion> additionalAttributes =
64+
singletonList(equalTo(MESSAGING_DESTINATION_NAME, "target-arn-foo"));
65+
66+
Object response =
67+
client.publish(
68+
new PublishRequest().withMessage("somemessage").withTargetArn("target-arn-foo"));
69+
assertRequestWithMockedResponse(
70+
response, client, "SNS", "Publish", "POST", additionalAttributes);
71+
}
5472

55-
server.enqueue(HttpResponse.of(HttpStatus.OK, MediaType.PLAIN_TEXT_UTF_8, body));
73+
@Test
74+
public void testPublishRequestWithTopicArnAndMockedResponse() throws Exception {
75+
AmazonSNSClientBuilder clientBuilder = AmazonSNSClientBuilder.standard();
76+
AmazonSNS client =
77+
configureClient(clientBuilder)
78+
.withEndpointConfiguration(endpoint)
79+
.withCredentials(credentialsProvider)
80+
.build();
5681

82+
server.enqueue(HttpResponse.of(HttpStatus.OK, MediaType.PLAIN_TEXT_UTF_8, publishResponseBody));
5783
List<AttributeAssertion> additionalAttributes =
58-
singletonList(equalTo(MESSAGING_DESTINATION_NAME, "somearn"));
84+
asList(
85+
equalTo(MESSAGING_DESTINATION_NAME, "topic-arn-foo"),
86+
equalTo(AWS_SNS_TOPIC_ARN, "topic-arn-foo"));
87+
88+
Object response =
89+
client.publish(
90+
new PublishRequest().withMessage("somemessage").withTopicArn("topic-arn-foo"));
5991

60-
Object response = call.apply(client);
6192
assertRequestWithMockedResponse(
6293
response, client, "SNS", "Publish", "POST", additionalAttributes);
6394
}
6495

65-
private static Stream<Arguments> provideArguments() {
66-
return Stream.of(
67-
Arguments.of(
68-
(Function<AmazonSNS, Object>)
69-
c ->
70-
c.publish(
71-
new PublishRequest().withMessage("somemessage").withTopicArn("somearn"))),
72-
Arguments.of(
73-
(Function<AmazonSNS, Object>)
74-
c ->
75-
c.publish(
76-
new PublishRequest().withMessage("somemessage").withTargetArn("somearn"))));
96+
@Test
97+
public void testCreateTopicRequestWithMockedResponse() throws Exception {
98+
AmazonSNSClientBuilder clientBuilder = AmazonSNSClientBuilder.standard();
99+
AmazonSNS client =
100+
configureClient(clientBuilder)
101+
.withEndpointConfiguration(endpoint)
102+
.withCredentials(credentialsProvider)
103+
.build();
104+
105+
server.enqueue(
106+
HttpResponse.of(HttpStatus.OK, MediaType.PLAIN_TEXT_UTF_8, createTopicResponseBody));
107+
List<AttributeAssertion> additionalAttributes =
108+
asList(equalTo(AWS_SNS_TOPIC_ARN, "arn:aws:sns:us-east-1:123456789012:sns-topic-foo"));
109+
110+
Object response = client.createTopic(new CreateTopicRequest().withName("sns-topic-foo"));
111+
112+
assertRequestWithMockedResponse(
113+
response, client, "SNS", "CreateTopic", "POST", additionalAttributes);
77114
}
78115
}

instrumentation/aws-sdk/aws-sdk-2.2/library/src/main/java/io/opentelemetry/instrumentation/awssdk/v2_2/internal/AwsSdkRequestType.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,9 @@ enum AwsSdkRequestType {
2626
* Only one of TopicArn and TargetArn are permitted on an SNS request.
2727
*/
2828
request(AttributeKeys.MESSAGING_DESTINATION_NAME.getKey(), "TargetArn"),
29-
request(AttributeKeys.MESSAGING_DESTINATION_NAME.getKey(), "TopicArn")),
29+
request(AttributeKeys.MESSAGING_DESTINATION_NAME.getKey(), "TopicArn"),
30+
request(AttributeKeys.AWS_SNS_TOPIC_ARN.getKey(), "TopicArn"),
31+
response(AttributeKeys.AWS_SNS_TOPIC_ARN.getKey(), "TopicArn")),
3032
STEPFUNCTIONS(
3133
request(AttributeKeys.AWS_STEP_FUNCTIONS_STATE_MACHINE_ARN.getKey(), "stateMachineArn"),
3234
request(AttributeKeys.AWS_STEP_FUNCTIONS_ACTIVITY_ARN.getKey(), "activityArn"));
@@ -47,6 +49,7 @@ private static class AttributeKeys {
4749
// Copied from AwsIncubatingAttributes
4850
static final AttributeKey<String> AWS_SECRETSMANAGER_SECRET_ARN =
4951
stringKey("aws.secretsmanager.secret.arn");
52+
static final AttributeKey<String> AWS_SNS_TOPIC_ARN = stringKey("aws.sns.topic.arn");
5053
static final AttributeKey<String> AWS_STEP_FUNCTIONS_ACTIVITY_ARN =
5154
stringKey("aws.step_functions.activity.arn");
5255
static final AttributeKey<String> AWS_STEP_FUNCTIONS_STATE_MACHINE_ARN =

0 commit comments

Comments
 (0)