diff --git a/instrumentation/aws-sdk/aws-sdk-1.11/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/awssdk/v1_11/AwsSpanAssertions.java b/instrumentation/aws-sdk/aws-sdk-1.11/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/awssdk/v1_11/AwsSpanAssertions.java index bb2656605048..954d72231b58 100644 --- a/instrumentation/aws-sdk/aws-sdk-1.11/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/awssdk/v1_11/AwsSpanAssertions.java +++ b/instrumentation/aws-sdk/aws-sdk-1.11/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/awssdk/v1_11/AwsSpanAssertions.java @@ -15,6 +15,7 @@ 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_SNS_TOPIC_ARN; import static io.opentelemetry.semconv.incubating.MessagingIncubatingAttributes.MESSAGING_DESTINATION_NAME; import static io.opentelemetry.semconv.incubating.RpcIncubatingAttributes.RPC_METHOD; import static io.opentelemetry.semconv.incubating.RpcIncubatingAttributes.RPC_SERVICE; @@ -90,6 +91,7 @@ static SpanDataAssert sns(SpanDataAssert span, String topicArn, String rpcMethod .hasAttributesSatisfyingExactly( equalTo(stringKey("aws.agent"), "java-aws-sdk"), equalTo(MESSAGING_DESTINATION_NAME, topicArn), + satisfies(AWS_SNS_TOPIC_ARN, v -> v.isInstanceOf(String.class)), satisfies(AWS_REQUEST_ID, v -> v.isInstanceOf(String.class)), equalTo(RPC_METHOD, rpcMethod), equalTo(RPC_SYSTEM, "aws-api"), diff --git a/instrumentation/aws-sdk/aws-sdk-1.11/library/src/main/java/io/opentelemetry/instrumentation/awssdk/v1_11/AwsSdkAttributesExtractor.java b/instrumentation/aws-sdk/aws-sdk-1.11/library/src/main/java/io/opentelemetry/instrumentation/awssdk/v1_11/AwsSdkAttributesExtractor.java index 57bbd87105c8..e267a958711b 100644 --- a/instrumentation/aws-sdk/aws-sdk-1.11/library/src/main/java/io/opentelemetry/instrumentation/awssdk/v1_11/AwsSdkAttributesExtractor.java +++ b/instrumentation/aws-sdk/aws-sdk-1.11/library/src/main/java/io/opentelemetry/instrumentation/awssdk/v1_11/AwsSdkAttributesExtractor.java @@ -26,6 +26,7 @@ class AwsSdkAttributesExtractor implements AttributesExtractor, Respo // Copied from AwsIncubatingAttributes private static final AttributeKey AWS_SECRETSMANAGER_SECRET_ARN = stringKey("aws.secretsmanager.secret.arn"); + private static final AttributeKey AWS_SNS_TOPIC_ARN = stringKey("aws.sns.topic.arn"); private static final AttributeKey AWS_STEP_FUNCTIONS_ACTIVITY_ARN = stringKey("aws.step_functions.activity.arn"); private static final AttributeKey AWS_STEP_FUNCTIONS_STATE_MACHINE_ARN = @@ -45,6 +46,7 @@ private static boolean canGetResponseMetadata() { @Override public void onStart(AttributesBuilder attributes, Context parentContext, Request request) { Object originalRequest = request.getOriginalRequest(); + setAttribute(attributes, AWS_SNS_TOPIC_ARN, originalRequest, RequestAccess::getSnsTopicArn); setAttribute( attributes, AWS_STEP_FUNCTIONS_STATE_MACHINE_ARN, @@ -67,6 +69,7 @@ public void onEnd( Object awsResp = getAwsResponse(response); if (awsResp != null) { setAttribute(attributes, AWS_SECRETSMANAGER_SECRET_ARN, awsResp, RequestAccess::getSecretArn); + setAttribute(attributes, AWS_SNS_TOPIC_ARN, awsResp, RequestAccess::getSnsTopicArn); setAttribute( attributes, AWS_STEP_FUNCTIONS_STATE_MACHINE_ARN, diff --git a/instrumentation/aws-sdk/aws-sdk-1.11/library/src/main/java/io/opentelemetry/instrumentation/awssdk/v1_11/RequestAccess.java b/instrumentation/aws-sdk/aws-sdk-1.11/library/src/main/java/io/opentelemetry/instrumentation/awssdk/v1_11/RequestAccess.java index 2658cd12448f..537b9d997c58 100644 --- a/instrumentation/aws-sdk/aws-sdk-1.11/library/src/main/java/io/opentelemetry/instrumentation/awssdk/v1_11/RequestAccess.java +++ b/instrumentation/aws-sdk/aws-sdk-1.11/library/src/main/java/io/opentelemetry/instrumentation/awssdk/v1_11/RequestAccess.java @@ -73,7 +73,7 @@ static String getTableName(Object request) { } @Nullable - static String getTopicArn(Object request) { + static String getSnsTopicArn(Object request) { RequestAccess access = REQUEST_ACCESSORS.get(request.getClass()); return invokeOrNull(access.getTopicArn, request); } diff --git a/instrumentation/aws-sdk/aws-sdk-1.11/library/src/main/java/io/opentelemetry/instrumentation/awssdk/v1_11/SnsAttributesExtractor.java b/instrumentation/aws-sdk/aws-sdk-1.11/library/src/main/java/io/opentelemetry/instrumentation/awssdk/v1_11/SnsAttributesExtractor.java index 541db9291363..2874e4c82538 100644 --- a/instrumentation/aws-sdk/aws-sdk-1.11/library/src/main/java/io/opentelemetry/instrumentation/awssdk/v1_11/SnsAttributesExtractor.java +++ b/instrumentation/aws-sdk/aws-sdk-1.11/library/src/main/java/io/opentelemetry/instrumentation/awssdk/v1_11/SnsAttributesExtractor.java @@ -32,7 +32,7 @@ public void onStart(AttributesBuilder attributes, Context parentContext, Request * falling back to the target ARN. If neither is found null is returned. */ private static String findMessageDestination(AmazonWebServiceRequest request) { - String destination = RequestAccess.getTopicArn(request); + String destination = RequestAccess.getSnsTopicArn(request); if (destination != null) { return destination; } diff --git a/instrumentation/aws-sdk/aws-sdk-1.11/testing/src/main/java/io/opentelemetry/instrumentation/awssdk/v1_11/AbstractSnsClientTest.java b/instrumentation/aws-sdk/aws-sdk-1.11/testing/src/main/java/io/opentelemetry/instrumentation/awssdk/v1_11/AbstractSnsClientTest.java index 3f272ba47713..49d794c6c1eb 100644 --- a/instrumentation/aws-sdk/aws-sdk-1.11/testing/src/main/java/io/opentelemetry/instrumentation/awssdk/v1_11/AbstractSnsClientTest.java +++ b/instrumentation/aws-sdk/aws-sdk-1.11/testing/src/main/java/io/opentelemetry/instrumentation/awssdk/v1_11/AbstractSnsClientTest.java @@ -6,11 +6,14 @@ package io.opentelemetry.instrumentation.awssdk.v1_11; import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.equalTo; +import static io.opentelemetry.semconv.incubating.AwsIncubatingAttributes.AWS_SNS_TOPIC_ARN; import static io.opentelemetry.semconv.incubating.MessagingIncubatingAttributes.MESSAGING_DESTINATION_NAME; +import static java.util.Arrays.asList; import static java.util.Collections.singletonList; import com.amazonaws.services.sns.AmazonSNS; import com.amazonaws.services.sns.AmazonSNSClientBuilder; +import com.amazonaws.services.sns.model.CreateTopicRequest; import com.amazonaws.services.sns.model.PublishRequest; import io.opentelemetry.sdk.testing.assertj.AttributeAssertion; import io.opentelemetry.testing.internal.armeria.common.HttpResponse; @@ -24,6 +27,25 @@ import org.junit.jupiter.params.provider.MethodSource; public abstract class AbstractSnsClientTest extends AbstractBaseAwsClientTest { + private static final String publishResponseBody = + "" + + " " + + " 567910cd-659e-55d4-8ccb-5aaf14679dc0" + + " " + + " " + + " d74b8436-ae13-5ab4-a9ff-ce54dfea72a0" + + " " + + ""; + + private static final String createTopicResponseBody = + "" + + " " + + " arn:aws:sns:us-east-1:123456789012:sns-topic-foo" + + " " + + " " + + " d74b8436-ae13-5ab4-a9ff-ce54dfea72a0" + + " " + + ""; public abstract AmazonSNSClientBuilder configureClient(AmazonSNSClientBuilder client); @@ -34,7 +56,12 @@ protected boolean hasRequestId() { @ParameterizedTest @MethodSource("provideArguments") - public void testSendRequestWithMockedResponse(Function call) throws Exception { + void testSendRequestWithMockedResponse( + Function call, + String operation, + String responseBody, + List additionalAttributes) + throws Exception { AmazonSNSClientBuilder clientBuilder = AmazonSNSClientBuilder.standard(); AmazonSNS client = configureClient(clientBuilder) @@ -42,24 +69,10 @@ public void testSendRequestWithMockedResponse(Function call) .withCredentials(credentialsProvider) .build(); - String body = - "" - + " " - + " 567910cd-659e-55d4-8ccb-5aaf14679dc0" - + " " - + " " - + " d74b8436-ae13-5ab4-a9ff-ce54dfea72a0" - + " " - + ""; - - server.enqueue(HttpResponse.of(HttpStatus.OK, MediaType.PLAIN_TEXT_UTF_8, body)); - - List additionalAttributes = - singletonList(equalTo(MESSAGING_DESTINATION_NAME, "somearn")); - + server.enqueue(HttpResponse.of(HttpStatus.OK, MediaType.PLAIN_TEXT_UTF_8, responseBody)); Object response = call.apply(client); assertRequestWithMockedResponse( - response, client, "SNS", "Publish", "POST", additionalAttributes); + response, client, "SNS", operation, "POST", additionalAttributes); } private static Stream provideArguments() { @@ -68,11 +81,26 @@ private static Stream provideArguments() { (Function) c -> c.publish( - new PublishRequest().withMessage("somemessage").withTopicArn("somearn"))), + new PublishRequest().withMessage("somemessage").withTopicArn("somearn")), + "Publish", + publishResponseBody, + asList( + equalTo(MESSAGING_DESTINATION_NAME, "somearn"), + equalTo(AWS_SNS_TOPIC_ARN, "somearn"))), Arguments.of( (Function) c -> c.publish( - new PublishRequest().withMessage("somemessage").withTargetArn("somearn")))); + new PublishRequest().withMessage("somemessage").withTargetArn("somearn")), + "Publish", + publishResponseBody, + singletonList(equalTo(MESSAGING_DESTINATION_NAME, "somearn"))), + Arguments.of( + (Function) + c -> c.createTopic(new CreateTopicRequest().withName("sns-topic-foo")), + "CreateTopic", + createTopicResponseBody, + singletonList( + equalTo(AWS_SNS_TOPIC_ARN, "arn:aws:sns:us-east-1:123456789012:sns-topic-foo")))); } } diff --git a/instrumentation/aws-sdk/aws-sdk-2.2/library/src/main/java/io/opentelemetry/instrumentation/awssdk/v2_2/internal/AwsSdkRequestType.java b/instrumentation/aws-sdk/aws-sdk-2.2/library/src/main/java/io/opentelemetry/instrumentation/awssdk/v2_2/internal/AwsSdkRequestType.java index f35b75f1bb82..962eba594b52 100644 --- a/instrumentation/aws-sdk/aws-sdk-2.2/library/src/main/java/io/opentelemetry/instrumentation/awssdk/v2_2/internal/AwsSdkRequestType.java +++ b/instrumentation/aws-sdk/aws-sdk-2.2/library/src/main/java/io/opentelemetry/instrumentation/awssdk/v2_2/internal/AwsSdkRequestType.java @@ -26,7 +26,9 @@ enum AwsSdkRequestType { * Only one of TopicArn and TargetArn are permitted on an SNS request. */ request(AttributeKeys.MESSAGING_DESTINATION_NAME.getKey(), "TargetArn"), - request(AttributeKeys.MESSAGING_DESTINATION_NAME.getKey(), "TopicArn")), + request(AttributeKeys.MESSAGING_DESTINATION_NAME.getKey(), "TopicArn"), + request(AttributeKeys.AWS_SNS_TOPIC_ARN.getKey(), "TopicArn"), + response(AttributeKeys.AWS_SNS_TOPIC_ARN.getKey(), "TopicArn")), STEPFUNCTIONS( request(AttributeKeys.AWS_STEP_FUNCTIONS_STATE_MACHINE_ARN.getKey(), "stateMachineArn"), request(AttributeKeys.AWS_STEP_FUNCTIONS_ACTIVITY_ARN.getKey(), "activityArn")); @@ -47,6 +49,7 @@ private static class AttributeKeys { // Copied from AwsIncubatingAttributes static final AttributeKey AWS_SECRETSMANAGER_SECRET_ARN = stringKey("aws.secretsmanager.secret.arn"); + static final AttributeKey AWS_SNS_TOPIC_ARN = stringKey("aws.sns.topic.arn"); static final AttributeKey AWS_STEP_FUNCTIONS_ACTIVITY_ARN = stringKey("aws.step_functions.activity.arn"); static final AttributeKey AWS_STEP_FUNCTIONS_STATE_MACHINE_ARN = diff --git a/instrumentation/aws-sdk/aws-sdk-2.2/testing/src/main/java/io/opentelemetry/instrumentation/awssdk/v2_2/AbstractAws2ClientTest.java b/instrumentation/aws-sdk/aws-sdk-2.2/testing/src/main/java/io/opentelemetry/instrumentation/awssdk/v2_2/AbstractAws2ClientTest.java index 3def65b2b9a2..6629076e47d2 100644 --- a/instrumentation/aws-sdk/aws-sdk-2.2/testing/src/main/java/io/opentelemetry/instrumentation/awssdk/v2_2/AbstractAws2ClientTest.java +++ b/instrumentation/aws-sdk/aws-sdk-2.2/testing/src/main/java/io/opentelemetry/instrumentation/awssdk/v2_2/AbstractAws2ClientTest.java @@ -15,6 +15,7 @@ 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.AwsIncubatingAttributes.AWS_SNS_TOPIC_ARN; import static io.opentelemetry.semconv.incubating.AwsIncubatingAttributes.AWS_STEP_FUNCTIONS_ACTIVITY_ARN; import static io.opentelemetry.semconv.incubating.AwsIncubatingAttributes.AWS_STEP_FUNCTIONS_STATE_MACHINE_ARN; import static io.opentelemetry.semconv.incubating.MessagingIncubatingAttributes.MESSAGING_DESTINATION_NAME; @@ -98,7 +99,12 @@ import software.amazon.awssdk.services.sns.SnsAsyncClientBuilder; import software.amazon.awssdk.services.sns.SnsClient; import software.amazon.awssdk.services.sns.SnsClientBuilder; +import software.amazon.awssdk.services.sns.model.CreateTopicRequest; +import software.amazon.awssdk.services.sns.model.CreateTopicResponse; import software.amazon.awssdk.services.sns.model.PublishRequest; +import software.amazon.awssdk.services.sns.model.PublishResponse; +import software.amazon.awssdk.services.sns.model.SubscribeRequest; +import software.amazon.awssdk.services.sns.model.SubscribeResponse; import software.amazon.awssdk.services.sqs.SqsAsyncClient; import software.amazon.awssdk.services.sqs.SqsAsyncClientBuilder; import software.amazon.awssdk.services.sqs.SqsClient; @@ -139,6 +145,36 @@ public abstract class AbstractAws2ClientTest extends AbstractAws2ClientCoreTest + " \"CreatedDate\": \"1.523477145713E9\"" + "}"; + private static final String snsPublishResponseBody = + "" + + " " + + " 567910cd-659e-55d4-8ccb-5aaf14679dc0" + + " " + + " " + + " d74b8436-ae13-5ab4-a9ff-ce54dfea72a0" + + " " + + ""; + + private static final String snsSubscribeResponseBody = + "" + + " " + + " arn:aws:sns:us-west-2:123456789012:MyTopic:abc123" + + " " + + " " + + " 0ac9cda2-abcd-11d3-f92b-31fa5e8dbc67" + + " " + + " "; + + private static final String snsCreateTopicResponseBody = + "" + + " " + + " arn:aws:sns:us-east-1:123456789012:sns-topic-name-foo" + + " " + + " " + + " d74b8436-ae13-5ab4-a9ff-ce54dfea72a0" + + " " + + ""; + private static void assumeSupportedConfig(String operation) { Assumptions.assumeFalse( operation.equals("SendMessage") && isSqsAttributeInjectionEnabled(), @@ -223,7 +259,22 @@ private void clientAssertions( } if (service.equals("Sns")) { - attributes.add(equalTo(MESSAGING_DESTINATION_NAME, "somearn")); + switch (operation) { + case "CreateTopic": + attributes.add( + equalTo(AWS_SNS_TOPIC_ARN, "arn:aws:sns:us-east-1:123456789012:sns-topic-name-foo")); + break; + case "Publish": + attributes.add(equalTo(MESSAGING_DESTINATION_NAME, "sns-target-arn")); + break; + case "Subscribe": + attributes.add(equalTo(MESSAGING_DESTINATION_NAME, "sns-topic-arn")); + attributes.add(equalTo(AWS_SNS_TOPIC_ARN, "sns-topic-arn")); + break; + default: + attributes.add(equalTo(AWS_SNS_TOPIC_ARN, "Bug-Unknown-Operation-ARN")); + break; + } } if (service.equals("Sqs") && operation.equals("CreateQueue")) { @@ -516,22 +567,43 @@ private static Stream provideSnsArguments() { c -> c.publish( PublishRequest.builder() - .message("somemessage") - .topicArn("somearn") - .build())), + .message("sns-msg-foo") + .targetArn("sns-target-arn") + .build()), + "Publish", + "POST", + snsPublishResponseBody, + "d74b8436-ae13-5ab4-a9ff-ce54dfea72a0"), Arguments.of( (Function) c -> - c.publish( - PublishRequest.builder() - .message("somemessage") - .targetArn("somearn") - .build()))); + c.subscribe( + SubscribeRequest.builder() + .topicArn("sns-topic-arn") + .protocol("email") + .endpoint("test@example.com") + .build()), + "Subscribe", + "POST", + snsSubscribeResponseBody, + "0ac9cda2-abcd-11d3-f92b-31fa5e8dbc67"), + Arguments.of( + (Function) + c -> c.createTopic(CreateTopicRequest.builder().name("sns-topic-name-foo").build()), + "CreateTopic", + "POST", + snsCreateTopicResponseBody, + "d74b8436-ae13-5ab4-a9ff-ce54dfea72a0")); } @ParameterizedTest @MethodSource("provideSnsArguments") - void testSnsSendOperationRequestWithBuilder(Function call) { + void testSnsSendOperationRequestWithBuilder( + Function call, + String operation, + String method, + String responseBody, + String requestId) { SnsClientBuilder builder = SnsClient.builder(); configureSdkClient(builder); SnsClient client = @@ -541,28 +613,25 @@ void testSnsSendOperationRequestWithBuilder(Function call) { .credentialsProvider(CREDENTIALS_PROVIDER) .build(); - String body = - "" - + " " - + " 567910cd-659e-55d4-8ccb-5aaf14679dc0" - + " " - + " " - + " d74b8436-ae13-5ab4-a9ff-ce54dfea72a0" - + " " - + ""; - - server.enqueue(HttpResponse.of(HttpStatus.OK, MediaType.PLAIN_TEXT_UTF_8, body)); + server.enqueue(HttpResponse.of(HttpStatus.OK, MediaType.PLAIN_TEXT_UTF_8, responseBody)); Object response = call.apply(client); assertThat(response.getClass().getSimpleName()) .satisfiesAnyOf( - v -> assertThat(v).startsWith("Publish"), - v -> assertThat(response).isInstanceOf(ResponseInputStream.class)); - clientAssertions("Sns", "Publish", "POST", response, "d74b8436-ae13-5ab4-a9ff-ce54dfea72a0"); + v -> assertThat(response).isInstanceOf(CreateTopicResponse.class), + v -> assertThat(response).isInstanceOf(PublishResponse.class), + v -> assertThat(response).isInstanceOf(SubscribeResponse.class)); + clientAssertions("Sns", operation, method, response, requestId); } - @Test - void testSnsAsyncSendOperationRequestWithBuilder() { + @ParameterizedTest + @MethodSource("provideSnsArguments") + void testSnsAsyncSendOperationRequestWithBuilder( + Function call, + String operation, + String method, + String responseBody, + String requestId) { SnsAsyncClientBuilder builder = SnsAsyncClient.builder(); configureSdkClient(builder); SnsAsyncClient client = @@ -572,20 +641,15 @@ void testSnsAsyncSendOperationRequestWithBuilder() { .credentialsProvider(CREDENTIALS_PROVIDER) .build(); - String body = - "" - + " " - + " 94f20ce6-13c5-43a0-9a9e-ca52d816e90b" - + " " - + " " - + " f187a3c1-376f-11df-8963-01868b7c937a" - + " " - + ""; - - server.enqueue(HttpResponse.of(HttpStatus.OK, MediaType.PLAIN_TEXT_UTF_8, body)); - Object response = client.publish(r -> r.message("hello").topicArn("somearn")); + server.enqueue(HttpResponse.of(HttpStatus.OK, MediaType.PLAIN_TEXT_UTF_8, responseBody)); + Object response = call.apply(wrapClient(SnsClient.class, SnsAsyncClient.class, client)); - clientAssertions("Sns", "Publish", "POST", response, "f187a3c1-376f-11df-8963-01868b7c937a"); + assertThat(response.getClass().getSimpleName()) + .satisfiesAnyOf( + v -> assertThat(response).isInstanceOf(CreateTopicResponse.class), + v -> assertThat(response).isInstanceOf(PublishResponse.class), + v -> assertThat(response).isInstanceOf(SubscribeResponse.class)); + clientAssertions("Sns", operation, method, response, requestId); } @Test