Fix http attributes of AWS SDK V2 instrumentation (#8931)
Signed-off-by: Raphael Silva <rapphil@gmail.com> Co-authored-by: Jean Bisutti <jean.bisutti@gmail.com>
This commit is contained in:
parent
55368a52d7
commit
57cfddcdd0
|
@ -81,6 +81,7 @@ dependencies {
|
|||
testLibrary("software.amazon.awssdk:s3:2.2.0")
|
||||
testLibrary("software.amazon.awssdk:sqs:2.2.0")
|
||||
testLibrary("software.amazon.awssdk:sns:2.2.0")
|
||||
testLibrary("software.amazon.awssdk:ses:2.2.0")
|
||||
}
|
||||
|
||||
tasks {
|
||||
|
@ -95,7 +96,6 @@ tasks {
|
|||
}
|
||||
|
||||
withType<Test>().configureEach {
|
||||
systemProperty("testLatestDeps", findProperty("testLatestDeps") as Boolean)
|
||||
// TODO run tests both with and without experimental span attributes
|
||||
systemProperty("otel.instrumentation.aws-sdk.experimental-span-attributes", "true")
|
||||
}
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
/*
|
||||
* Copyright The OpenTelemetry Authors
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
import io.opentelemetry.instrumentation.awssdk.v2_2.AbstractQueryProtocolModelTest;
|
||||
import io.opentelemetry.instrumentation.testing.junit.AgentInstrumentationExtension;
|
||||
import io.opentelemetry.instrumentation.testing.junit.InstrumentationExtension;
|
||||
import org.junit.jupiter.api.extension.RegisterExtension;
|
||||
import software.amazon.awssdk.core.client.config.ClientOverrideConfiguration;
|
||||
|
||||
class QueryProtocolModelTest extends AbstractQueryProtocolModelTest {
|
||||
@RegisterExtension
|
||||
private final AgentInstrumentationExtension testing = AgentInstrumentationExtension.create();
|
||||
|
||||
@Override
|
||||
protected ClientOverrideConfiguration.Builder createClientOverrideConfigurationBuilder() {
|
||||
return ClientOverrideConfiguration.builder();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected InstrumentationExtension getTesting() {
|
||||
return testing;
|
||||
}
|
||||
}
|
|
@ -23,7 +23,6 @@ dependencies {
|
|||
|
||||
tasks {
|
||||
test {
|
||||
systemProperty("testLatestDeps", findProperty("testLatestDeps") as Boolean)
|
||||
systemProperty("otel.instrumentation.aws-sdk.experimental-span-attributes", true)
|
||||
systemProperty("otel.instrumentation.aws-sdk.experimental-use-propagator-for-messaging", true)
|
||||
}
|
||||
|
|
|
@ -18,6 +18,7 @@ dependencies {
|
|||
testLibrary("software.amazon.awssdk:kinesis:2.2.0")
|
||||
testLibrary("software.amazon.awssdk:rds:2.2.0")
|
||||
testLibrary("software.amazon.awssdk:s3:2.2.0")
|
||||
testLibrary("software.amazon.awssdk:ses:2.2.0")
|
||||
}
|
||||
|
||||
testing {
|
||||
|
@ -42,8 +43,6 @@ testing {
|
|||
|
||||
tasks {
|
||||
withType<Test> {
|
||||
systemProperty("testLatestDeps", findProperty("testLatestDeps") as Boolean)
|
||||
|
||||
// NB: If you'd like to change these, there is some cleanup work to be done, as most tests ignore this and
|
||||
// set the value directly (the "library" does not normally query it, only library-autoconfigure)
|
||||
systemProperty("otel.instrumentation.aws-sdk.experimental-span-attributes", true)
|
||||
|
|
|
@ -137,9 +137,13 @@ final class TracingExecutionInterceptor implements ExecutionInterceptor {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void afterMarshalling(
|
||||
Context.AfterMarshalling context, ExecutionAttributes executionAttributes) {
|
||||
|
||||
public void beforeTransmission(
|
||||
Context.BeforeTransmission context, ExecutionAttributes executionAttributes) {
|
||||
// In beforeTransmission we get access to the finalized http request, including modifications
|
||||
// performed by other interceptors and the message signature.
|
||||
// It is unlikely that further modifications are performed by the http client performing the
|
||||
// request given that this would require the signature to be regenerated.
|
||||
//
|
||||
// Since we merge the HTTP attributes into an already started span instead of creating a
|
||||
// full child span, we have to do some dirty work here.
|
||||
//
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
/*
|
||||
* Copyright The OpenTelemetry Authors
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package io.opentelemetry.instrumentation.awssdk.v2_2;
|
||||
|
||||
import io.opentelemetry.instrumentation.testing.junit.InstrumentationExtension;
|
||||
import io.opentelemetry.instrumentation.testing.junit.LibraryInstrumentationExtension;
|
||||
import org.junit.jupiter.api.extension.RegisterExtension;
|
||||
import software.amazon.awssdk.core.client.config.ClientOverrideConfiguration;
|
||||
|
||||
class QueryProtocolModelTest extends AbstractQueryProtocolModelTest {
|
||||
@RegisterExtension
|
||||
public final LibraryInstrumentationExtension testing = LibraryInstrumentationExtension.create();
|
||||
|
||||
@Override
|
||||
protected ClientOverrideConfiguration.Builder createClientOverrideConfigurationBuilder() {
|
||||
return ClientOverrideConfiguration.builder()
|
||||
.addExecutionInterceptor(
|
||||
AwsSdkTelemetry.builder(testing.getOpenTelemetry()).build().newExecutionInterceptor());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected InstrumentationExtension getTesting() {
|
||||
return testing;
|
||||
}
|
||||
}
|
|
@ -18,6 +18,7 @@ dependencies {
|
|||
compileOnly("software.amazon.awssdk:s3:2.2.0")
|
||||
compileOnly("software.amazon.awssdk:sqs:2.2.0")
|
||||
compileOnly("software.amazon.awssdk:sns:2.2.0")
|
||||
compileOnly("software.amazon.awssdk:ses:2.2.0")
|
||||
|
||||
// needed for SQS - using emq directly as localstack references emq v0.15.7 ie WITHOUT AWS trace header propagation
|
||||
implementation("org.elasticmq:elasticmq-rest-sqs_2.12:1.0.0")
|
||||
|
|
|
@ -52,13 +52,18 @@ abstract class AbstractAws2ClientTest extends AbstractAws2ClientCoreTest {
|
|||
"Cannot check Sqs.SendMessage here due to hard-coded MD5.")
|
||||
}
|
||||
|
||||
// Force localhost instead of relying on mock server because using ip is yet another corner case of the virtual
|
||||
// bucket changes introduced by aws sdk v2.18.0. When using IP, there is no way to prefix the hostname with the
|
||||
// bucket name as label.
|
||||
def clientUri = URI.create("http://localhost:${server.httpPort()}")
|
||||
|
||||
def "send #operation request with builder #builder.class.getName() mocked response"() {
|
||||
assumeSupportedConfig(service, operation)
|
||||
|
||||
setup:
|
||||
configureSdkClient(builder)
|
||||
def client = builder
|
||||
.endpointOverride(server.httpUri())
|
||||
.endpointOverride(clientUri)
|
||||
.region(Region.AP_NORTHEAST_1)
|
||||
.credentialsProvider(CREDENTIALS_PROVIDER)
|
||||
.build()
|
||||
|
@ -80,9 +85,18 @@ abstract class AbstractAws2ClientTest extends AbstractAws2ClientCoreTest {
|
|||
kind operation != "SendMessage" ? CLIENT : PRODUCER
|
||||
hasNoParent()
|
||||
attributes {
|
||||
"$SemanticAttributes.NET_PEER_NAME" "127.0.0.1"
|
||||
if (service == "S3") {
|
||||
// Starting with AWS SDK V2 2.18.0, the s3 sdk will prefix the hostname with the bucket name in case
|
||||
// the bucket name is a valid DNS label, even in the case that we are using an endpoint override.
|
||||
// Previously the sdk was only doing that if endpoint had "s3" as label in the FQDN.
|
||||
// Our test assert both cases so that we don't need to know what version is being tested.
|
||||
"$SemanticAttributes.NET_PEER_NAME" { it == "somebucket.localhost" || it == "localhost" }
|
||||
"$SemanticAttributes.HTTP_URL" { it.startsWith("http://somebucket.localhost:${server.httpPort()}") || it.startsWith("http://localhost:${server.httpPort()}/somebucket") }
|
||||
} else {
|
||||
"$SemanticAttributes.NET_PEER_NAME" "localhost"
|
||||
"$SemanticAttributes.HTTP_URL" { it.startsWith("http://localhost:${server.httpPort()}") }
|
||||
}
|
||||
"$SemanticAttributes.NET_PEER_PORT" server.httpPort()
|
||||
"$SemanticAttributes.HTTP_URL" { it.startsWith("${server.httpUri()}${path}") }
|
||||
"$SemanticAttributes.HTTP_METHOD" "$method"
|
||||
"$SemanticAttributes.HTTP_STATUS_CODE" 200
|
||||
"$SemanticAttributes.USER_AGENT_ORIGINAL" { it.startsWith("aws-sdk-java/") }
|
||||
|
@ -111,17 +125,17 @@ abstract class AbstractAws2ClientTest extends AbstractAws2ClientCoreTest {
|
|||
request.request().headers().get("traceparent") == null
|
||||
|
||||
where:
|
||||
service | operation | method | path | requestId | builder | call | body
|
||||
"S3" | "CreateBucket" | "PUT" | path("somebucket") | "UNKNOWN" | S3Client.builder() | { c -> c.createBucket(CreateBucketRequest.builder().bucket("somebucket").build()) } | ""
|
||||
"S3" | "GetObject" | "GET" | path("somebucket", "somekey") | "UNKNOWN" | S3Client.builder() | { c -> c.getObject(GetObjectRequest.builder().bucket("somebucket").key("somekey").build()) } | ""
|
||||
"Kinesis" | "DeleteStream" | "POST" | "" | "UNKNOWN" | KinesisClient.builder() | { c -> c.deleteStream(DeleteStreamRequest.builder().streamName("somestream").build()) } | ""
|
||||
"Sqs" | "CreateQueue" | "POST" | "" | "7a62c49f-347e-4fc4-9331-6e8e7a96aa73" | SqsClient.builder() | { c -> c.createQueue(CreateQueueRequest.builder().queueName("somequeue").build()) } | """
|
||||
service | operation | method | requestId | builder | call | body
|
||||
"S3" | "CreateBucket" | "PUT" | "UNKNOWN" | S3Client.builder() | { c -> c.createBucket(CreateBucketRequest.builder().bucket("somebucket").build()) } | ""
|
||||
"S3" | "GetObject" | "GET" | "UNKNOWN" | S3Client.builder() | { c -> c.getObject(GetObjectRequest.builder().bucket("somebucket").key("somekey").build()) } | ""
|
||||
"Kinesis" | "DeleteStream" | "POST" | "UNKNOWN" | KinesisClient.builder() | { c -> c.deleteStream(DeleteStreamRequest.builder().streamName("somestream").build()) } | ""
|
||||
"Sqs" | "CreateQueue" | "POST" | "7a62c49f-347e-4fc4-9331-6e8e7a96aa73" | SqsClient.builder() | { c -> c.createQueue(CreateQueueRequest.builder().queueName("somequeue").build()) } | """
|
||||
<CreateQueueResponse>
|
||||
<CreateQueueResult><QueueUrl>https://queue.amazonaws.com/123456789012/MyQueue</QueueUrl></CreateQueueResult>
|
||||
<ResponseMetadata><RequestId>7a62c49f-347e-4fc4-9331-6e8e7a96aa73</RequestId></ResponseMetadata>
|
||||
</CreateQueueResponse>
|
||||
"""
|
||||
"Sqs" | "SendMessage" | "POST" | "" | "27daac76-34dd-47df-bd01-1f6e873584a0" | SqsClient.builder() | { c -> c.sendMessage(SendMessageRequest.builder().queueUrl("someurl").messageBody("").build()) } | """
|
||||
"Sqs" | "SendMessage" | "POST" | "27daac76-34dd-47df-bd01-1f6e873584a0" | SqsClient.builder() | { c -> c.sendMessage(SendMessageRequest.builder().queueUrl("someurl").messageBody("").build()) } | """
|
||||
<SendMessageResponse>
|
||||
<SendMessageResult>
|
||||
<MD5OfMessageBody>d41d8cd98f00b204e9800998ecf8427e</MD5OfMessageBody>
|
||||
|
@ -131,14 +145,14 @@ abstract class AbstractAws2ClientTest extends AbstractAws2ClientCoreTest {
|
|||
<ResponseMetadata><RequestId>27daac76-34dd-47df-bd01-1f6e873584a0</RequestId></ResponseMetadata>
|
||||
</SendMessageResponse>
|
||||
"""
|
||||
"Ec2" | "AllocateAddress" | "POST" | "" | "59dbff89-35bd-4eac-99ed-be587EXAMPLE" | Ec2Client.builder() | { c -> c.allocateAddress() } | """
|
||||
"Ec2" | "AllocateAddress" | "POST" | "59dbff89-35bd-4eac-99ed-be587EXAMPLE" | Ec2Client.builder() | { c -> c.allocateAddress() } | """
|
||||
<AllocateAddressResponse xmlns="http://ec2.amazonaws.com/doc/2016-11-15/">
|
||||
<requestId>59dbff89-35bd-4eac-99ed-be587EXAMPLE</requestId>
|
||||
<publicIp>192.0.2.1</publicIp>
|
||||
<domain>standard</domain>
|
||||
</AllocateAddressResponse>
|
||||
"""
|
||||
"Rds" | "DeleteOptionGroup" | "POST" | "" | "0ac9cda2-bbf4-11d3-f92b-31fa5e8dbc99" | RdsClient.builder() | { c -> c.deleteOptionGroup(DeleteOptionGroupRequest.builder().build()) } | """
|
||||
"Rds" | "DeleteOptionGroup" | "POST" | "0ac9cda2-bbf4-11d3-f92b-31fa5e8dbc99" | RdsClient.builder() | { c -> c.deleteOptionGroup(DeleteOptionGroupRequest.builder().build()) } | """
|
||||
<DeleteOptionGroupResponse xmlns="http://rds.amazonaws.com/doc/2014-09-01/">
|
||||
<ResponseMetadata><RequestId>0ac9cda2-bbf4-11d3-f92b-31fa5e8dbc99</RequestId></ResponseMetadata>
|
||||
</DeleteOptionGroupResponse>
|
||||
|
@ -150,7 +164,7 @@ abstract class AbstractAws2ClientTest extends AbstractAws2ClientCoreTest {
|
|||
setup:
|
||||
configureSdkClient(builder)
|
||||
def client = builder
|
||||
.endpointOverride(server.httpUri())
|
||||
.endpointOverride(clientUri)
|
||||
.region(Region.AP_NORTHEAST_1)
|
||||
.credentialsProvider(CREDENTIALS_PROVIDER)
|
||||
.build()
|
||||
|
@ -171,9 +185,18 @@ abstract class AbstractAws2ClientTest extends AbstractAws2ClientCoreTest {
|
|||
kind operation != "SendMessage" ? CLIENT : PRODUCER
|
||||
hasNoParent()
|
||||
attributes {
|
||||
"$SemanticAttributes.NET_PEER_NAME" "127.0.0.1"
|
||||
if (service == "S3") {
|
||||
// Starting with AWS SDK V2 2.18.0, the s3 sdk will prefix the hostname with the bucket name in case
|
||||
// the bucket name is a valid DNS label, even in the case that we are using an endpoint override.
|
||||
// Previously the sdk was only doing that if endpoint had "s3" as label in the FQDN.
|
||||
// Our test assert both cases so that we don't need to know what version is being tested.
|
||||
"$SemanticAttributes.NET_PEER_NAME" { it == "somebucket.localhost" || it == "localhost" }
|
||||
"$SemanticAttributes.HTTP_URL" { it.startsWith("http://somebucket.localhost:${server.httpPort()}") || it.startsWith("http://localhost:${server.httpPort()}") }
|
||||
} else {
|
||||
"$SemanticAttributes.NET_PEER_NAME" "localhost"
|
||||
"$SemanticAttributes.HTTP_URL" "http://localhost:${server.httpPort()}"
|
||||
}
|
||||
"$SemanticAttributes.NET_PEER_PORT" server.httpPort()
|
||||
"$SemanticAttributes.HTTP_URL" { it.startsWith("${server.httpUri()}${path}") }
|
||||
"$SemanticAttributes.HTTP_METHOD" "$method"
|
||||
"$SemanticAttributes.HTTP_STATUS_CODE" 200
|
||||
"$SemanticAttributes.USER_AGENT_ORIGINAL" { it.startsWith("aws-sdk-java/") }
|
||||
|
@ -213,18 +236,18 @@ abstract class AbstractAws2ClientTest extends AbstractAws2ClientCoreTest {
|
|||
}
|
||||
|
||||
where:
|
||||
service | operation | method | path | requestId | builder | call | body
|
||||
"S3" | "CreateBucket" | "PUT" | path("somebucket") | "UNKNOWN" | S3AsyncClient.builder() | { c -> c.createBucket(CreateBucketRequest.builder().bucket("somebucket").build()) } | ""
|
||||
"S3" | "GetObject" | "GET" | path("somebucket", "somekey") | "UNKNOWN" | S3AsyncClient.builder() | { c -> c.getObject(GetObjectRequest.builder().bucket("somebucket").key("somekey").build(), AsyncResponseTransformer.toBytes()) } | "1234567890"
|
||||
service | operation | method | requestId | builder | call | body
|
||||
"S3" | "CreateBucket" | "PUT" | "UNKNOWN" | S3AsyncClient.builder() | { c -> c.createBucket(CreateBucketRequest.builder().bucket("somebucket").build()) } | ""
|
||||
"S3" | "GetObject" | "GET" | "UNKNOWN" | S3AsyncClient.builder() | { c -> c.getObject(GetObjectRequest.builder().bucket("somebucket").key("somekey").build(), AsyncResponseTransformer.toBytes()) } | "1234567890"
|
||||
// Kinesis seems to expect an http2 response which is incompatible with our test server.
|
||||
// "Kinesis" | "DeleteStream" | "POST" | "/" | "UNKNOWN" | KinesisAsyncClient.builder() | { c -> c.deleteStream(DeleteStreamRequest.builder().streamName("somestream").build()) } | ""
|
||||
"Sqs" | "CreateQueue" | "POST" | "" | "7a62c49f-347e-4fc4-9331-6e8e7a96aa73" | SqsAsyncClient.builder() | { c -> c.createQueue(CreateQueueRequest.builder().queueName("somequeue").build()) } | """
|
||||
"Sqs" | "CreateQueue" | "POST" | "7a62c49f-347e-4fc4-9331-6e8e7a96aa73" | SqsAsyncClient.builder() | { c -> c.createQueue(CreateQueueRequest.builder().queueName("somequeue").build()) } | """
|
||||
<CreateQueueResponse>
|
||||
<CreateQueueResult><QueueUrl>https://queue.amazonaws.com/123456789012/MyQueue</QueueUrl></CreateQueueResult>
|
||||
<ResponseMetadata><RequestId>7a62c49f-347e-4fc4-9331-6e8e7a96aa73</RequestId></ResponseMetadata>
|
||||
</CreateQueueResponse>
|
||||
"""
|
||||
"Sqs" | "SendMessage" | "POST" | "" | "27daac76-34dd-47df-bd01-1f6e873584a0" | SqsAsyncClient.builder() | { c -> c.sendMessage(SendMessageRequest.builder().queueUrl("someurl").messageBody("").build()) } | """
|
||||
"Sqs" | "SendMessage" | "POST" | "27daac76-34dd-47df-bd01-1f6e873584a0" | SqsAsyncClient.builder() | { c -> c.sendMessage(SendMessageRequest.builder().queueUrl("someurl").messageBody("").build()) } | """
|
||||
<SendMessageResponse>
|
||||
<SendMessageResult>
|
||||
<MD5OfMessageBody>d41d8cd98f00b204e9800998ecf8427e</MD5OfMessageBody>
|
||||
|
@ -234,19 +257,19 @@ abstract class AbstractAws2ClientTest extends AbstractAws2ClientCoreTest {
|
|||
<ResponseMetadata><RequestId>27daac76-34dd-47df-bd01-1f6e873584a0</RequestId></ResponseMetadata>
|
||||
</SendMessageResponse>
|
||||
"""
|
||||
"Ec2" | "AllocateAddress" | "POST" | "" | "59dbff89-35bd-4eac-99ed-be587EXAMPLE" | Ec2AsyncClient.builder() | { c -> c.allocateAddress() } | """
|
||||
"Ec2" | "AllocateAddress" | "POST" | "59dbff89-35bd-4eac-99ed-be587EXAMPLE" | Ec2AsyncClient.builder() | { c -> c.allocateAddress() } | """
|
||||
<AllocateAddressResponse xmlns="http://ec2.amazonaws.com/doc/2016-11-15/">
|
||||
<requestId>59dbff89-35bd-4eac-99ed-be587EXAMPLE</requestId>
|
||||
<publicIp>192.0.2.1</publicIp>
|
||||
<domain>standard</domain>
|
||||
</AllocateAddressResponse>
|
||||
"""
|
||||
"Rds" | "DeleteOptionGroup" | "POST" | "" | "0ac9cda2-bbf4-11d3-f92b-31fa5e8dbc99" | RdsAsyncClient.builder() | { c -> c.deleteOptionGroup(DeleteOptionGroupRequest.builder().build()) } | """
|
||||
"Rds" | "DeleteOptionGroup" | "POST" | "0ac9cda2-bbf4-11d3-f92b-31fa5e8dbc99" | RdsAsyncClient.builder() | { c -> c.deleteOptionGroup(DeleteOptionGroupRequest.builder().build()) } | """
|
||||
<DeleteOptionGroupResponse xmlns="http://rds.amazonaws.com/doc/2014-09-01/">
|
||||
<ResponseMetadata><RequestId>0ac9cda2-bbf4-11d3-f92b-31fa5e8dbc99</RequestId></ResponseMetadata>
|
||||
</DeleteOptionGroupResponse>
|
||||
"""
|
||||
"Sns" | "Publish" | "POST" | "" | "f187a3c1-376f-11df-8963-01868b7c937a" | SnsAsyncClient.builder() | { SnsAsyncClient c -> c.publish(r -> r.message("hello")) } | """
|
||||
"Sns" | "Publish" | "POST" | "f187a3c1-376f-11df-8963-01868b7c937a" | SnsAsyncClient.builder() | { SnsAsyncClient c -> c.publish(r -> r.message("hello")) } | """
|
||||
<PublishResponse xmlns="https://sns.amazonaws.com/doc/2010-03-31/">
|
||||
<PublishResult>
|
||||
<MessageId>94f20ce6-13c5-43a0-9a9e-ca52d816e90b</MessageId>
|
||||
|
@ -270,7 +293,7 @@ abstract class AbstractAws2ClientTest extends AbstractAws2ClientCoreTest {
|
|||
.overrideConfiguration(createOverrideConfigurationBuilder()
|
||||
.retryPolicy(RetryPolicy.builder().numRetries(1).build())
|
||||
.build())
|
||||
.endpointOverride(server.httpUri())
|
||||
.endpointOverride(clientUri)
|
||||
.region(Region.AP_NORTHEAST_1)
|
||||
.credentialsProvider(CREDENTIALS_PROVIDER)
|
||||
.httpClientBuilder(ApacheHttpClient.builder().socketTimeout(Duration.ofMillis(50)))
|
||||
|
@ -282,7 +305,6 @@ abstract class AbstractAws2ClientTest extends AbstractAws2ClientCoreTest {
|
|||
then:
|
||||
thrown SdkClientException
|
||||
|
||||
def path = path("somebucket", "somekey")
|
||||
assertTraces(1) {
|
||||
trace(0, 1) {
|
||||
span(0) {
|
||||
|
@ -292,13 +314,18 @@ abstract class AbstractAws2ClientTest extends AbstractAws2ClientCoreTest {
|
|||
errorEvent SdkClientException, "Unable to execute HTTP request: Read timed out"
|
||||
hasNoParent()
|
||||
attributes {
|
||||
"$SemanticAttributes.NET_PEER_NAME" "127.0.0.1"
|
||||
// Starting with AWS SDK V2 2.18.0, the s3 sdk will prefix the hostname with the bucket name in case
|
||||
// the bucket name is a valid DNS label, even in the case that we are using an endpoint override.
|
||||
// Previously the sdk was only doing that if endpoint had "s3" as label in the FQDN.
|
||||
// Our test assert both cases so that we don't need to know what version is being tested.
|
||||
"$SemanticAttributes.NET_PEER_NAME" { it == "somebucket.localhost" || it == "localhost" }
|
||||
"$SemanticAttributes.HTTP_URL" { it == "http://somebucket.localhost:${server.httpPort()}/somekey" || it == "http://localhost:${server.httpPort()}/somebucket/somekey" }
|
||||
"$SemanticAttributes.NET_PEER_PORT" server.httpPort()
|
||||
"$SemanticAttributes.HTTP_URL" "${server.httpUri()}${path}"
|
||||
"$SemanticAttributes.HTTP_METHOD" "GET"
|
||||
"$SemanticAttributes.RPC_SYSTEM" "aws-api"
|
||||
"$SemanticAttributes.RPC_SERVICE" "S3"
|
||||
"$SemanticAttributes.RPC_METHOD" "GetObject"
|
||||
"$SemanticAttributes.USER_AGENT_ORIGINAL" String
|
||||
"aws.agent" "java-aws-sdk"
|
||||
"aws.bucket.name" "somebucket"
|
||||
}
|
||||
|
@ -306,16 +333,4 @@ abstract class AbstractAws2ClientTest extends AbstractAws2ClientCoreTest {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
static String path(String bucket, String path = null) {
|
||||
def result = ""
|
||||
// since 2.18.0 bucket name is not present in request path
|
||||
if (!Boolean.getBoolean("testLatestDeps") && !bucket.isEmpty()) {
|
||||
result = "/" + bucket
|
||||
}
|
||||
if (path != null && !path.isEmpty()) {
|
||||
result += "/" + path
|
||||
}
|
||||
return result
|
||||
}
|
||||
}
|
||||
|
|
|
@ -171,6 +171,7 @@ abstract class AbstractAws2SqsTracingTest extends InstrumentationSpecification {
|
|||
"http.method" "POST"
|
||||
"http.status_code" 200
|
||||
"http.url" { it.startsWith("http://localhost:$sqsPort") }
|
||||
"$SemanticAttributes.USER_AGENT_ORIGINAL" String
|
||||
"net.peer.name" "localhost"
|
||||
"net.peer.port" sqsPort
|
||||
"$SemanticAttributes.HTTP_REQUEST_CONTENT_LENGTH" { it == null || it instanceof Long }
|
||||
|
@ -310,6 +311,7 @@ abstract class AbstractAws2SqsTracingTest extends InstrumentationSpecification {
|
|||
"http.method" "POST"
|
||||
"http.status_code" 200
|
||||
"http.url" { it.startsWith("http://localhost:$sqsPort") }
|
||||
"$SemanticAttributes.USER_AGENT_ORIGINAL" String
|
||||
"net.peer.name" "localhost"
|
||||
"net.peer.port" sqsPort
|
||||
"$SemanticAttributes.HTTP_REQUEST_CONTENT_LENGTH" { it == null || it instanceof Long }
|
||||
|
@ -364,6 +366,7 @@ abstract class AbstractAws2SqsTracingTest extends InstrumentationSpecification {
|
|||
"http.status_code" 200
|
||||
"http.url" { it.startsWith("http://localhost:$sqsPort") }
|
||||
"net.peer.name" "localhost"
|
||||
"$SemanticAttributes.USER_AGENT_ORIGINAL" String
|
||||
"net.peer.port" sqsPort
|
||||
"$SemanticAttributes.HTTP_REQUEST_CONTENT_LENGTH" { it == null || it instanceof Long }
|
||||
"$SemanticAttributes.HTTP_RESPONSE_CONTENT_LENGTH" { it == null || it instanceof Long }
|
||||
|
|
|
@ -0,0 +1,110 @@
|
|||
/*
|
||||
* Copyright The OpenTelemetry Authors
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package io.opentelemetry.instrumentation.awssdk.v2_2;
|
||||
|
||||
import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.assertThat;
|
||||
import static io.opentelemetry.semconv.trace.attributes.SemanticAttributes.HTTP_URL;
|
||||
|
||||
import io.opentelemetry.api.trace.SpanKind;
|
||||
import io.opentelemetry.instrumentation.testing.junit.InstrumentationExtension;
|
||||
import io.opentelemetry.testing.internal.armeria.common.HttpResponse;
|
||||
import io.opentelemetry.testing.internal.armeria.common.HttpStatus;
|
||||
import io.opentelemetry.testing.internal.armeria.common.MediaType;
|
||||
import io.opentelemetry.testing.internal.armeria.testing.junit5.server.mock.MockWebServerExtension;
|
||||
import java.net.URI;
|
||||
import org.junit.jupiter.api.AfterAll;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.TestInstance;
|
||||
import software.amazon.awssdk.auth.credentials.AwsBasicCredentials;
|
||||
import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider;
|
||||
import software.amazon.awssdk.core.client.config.ClientOverrideConfiguration;
|
||||
import software.amazon.awssdk.regions.Region;
|
||||
import software.amazon.awssdk.services.ses.SesClient;
|
||||
import software.amazon.awssdk.services.ses.model.Body;
|
||||
import software.amazon.awssdk.services.ses.model.Content;
|
||||
import software.amazon.awssdk.services.ses.model.Destination;
|
||||
import software.amazon.awssdk.services.ses.model.Message;
|
||||
import software.amazon.awssdk.services.ses.model.SendEmailRequest;
|
||||
|
||||
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
|
||||
public abstract class AbstractQueryProtocolModelTest {
|
||||
private final MockWebServerExtension server = new MockWebServerExtension();
|
||||
|
||||
@BeforeAll
|
||||
public void setup() {
|
||||
server.start();
|
||||
}
|
||||
|
||||
@AfterAll
|
||||
public void end() {
|
||||
server.stop();
|
||||
}
|
||||
|
||||
@BeforeEach
|
||||
public void setupEach() {
|
||||
server.beforeTestExecution(null);
|
||||
}
|
||||
|
||||
protected abstract ClientOverrideConfiguration.Builder createClientOverrideConfigurationBuilder();
|
||||
|
||||
protected abstract InstrumentationExtension getTesting();
|
||||
|
||||
@Test
|
||||
void testClientWithQueryProtocolModel() {
|
||||
server.enqueue(
|
||||
HttpResponse.of(
|
||||
HttpStatus.OK,
|
||||
MediaType.PLAIN_TEXT_UTF_8,
|
||||
"<SendEmailResponse><MessageId>12345</MessageId></SendEmailResponse>"));
|
||||
SesClient ses =
|
||||
SesClient.builder()
|
||||
.endpointOverride(server.httpUri())
|
||||
.credentialsProvider(
|
||||
StaticCredentialsProvider.create(AwsBasicCredentials.create("foo", "bar")))
|
||||
.overrideConfiguration(createClientOverrideConfigurationBuilder().build())
|
||||
.region(Region.US_WEST_2)
|
||||
.build();
|
||||
|
||||
Destination destination = Destination.builder().toAddresses("dest@test.com").build();
|
||||
Content content = Content.builder().data("content").build();
|
||||
Content sub = Content.builder().data("subject").build();
|
||||
Body body = Body.builder().html(content).build();
|
||||
Message msg = Message.builder().subject(sub).body(body).build();
|
||||
SendEmailRequest emailRequest =
|
||||
SendEmailRequest.builder()
|
||||
.destination(destination)
|
||||
.message(msg)
|
||||
.source("source@test.com")
|
||||
.build();
|
||||
|
||||
ses.sendEmail(emailRequest);
|
||||
|
||||
getTesting()
|
||||
.waitAndAssertTraces(
|
||||
trace -> {
|
||||
trace.hasSpansSatisfyingExactly(
|
||||
span -> {
|
||||
span.hasKind(SpanKind.CLIENT);
|
||||
span.hasAttributesSatisfying(
|
||||
attributes -> {
|
||||
assertThat(attributes)
|
||||
.hasEntrySatisfying(
|
||||
HTTP_URL,
|
||||
entry -> {
|
||||
assertThat(entry)
|
||||
.satisfies(
|
||||
value -> {
|
||||
URI uri = URI.create(value);
|
||||
assertThat(uri.getQuery()).isNull();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue