Add additional tags for aws-sdk spans
s3 -> bucket name
dynamodb -> table name
sqs -> queue name/url
kinesis -> stream name
MODIFY
dd-java-agent/instrumentation/aws-java-sdk-2.2/aws-java-sdk-2.2.gradle
dd-java-agent/instrumentation/aws-java-sdk-2.2/aws-java-sdk-2.2.gradle
@@ -32,12 +32,19 @@ dependencies {
testCompile group: 'software.amazon.awssdk', name: 's3', version: '2.2.0'
testCompile group: 'software.amazon.awssdk', name: 'rds', version: '2.2.0'
testCompile group: 'software.amazon.awssdk', name: 'ec2', version: '2.2.0'
+ testCompile group: 'software.amazon.awssdk', name: 'sqs', version: '2.2.0'
+ testCompile group: 'software.amazon.awssdk', name: 'dynamodb', version: '2.2.0'
+ testCompile group: 'software.amazon.awssdk', name: 'kinesis', version: '2.2.0'
latestDepTestCompile project(':dd-java-agent:instrumentation:apache-httpclient-4')
latestDepTestCompile project(':dd-java-agent:instrumentation:netty-4.1')
latestDepTestCompile project(':dd-java-agent:instrumentation:java-concurrent')
+
latestDepTestCompile group: 'software.amazon.awssdk', name: 'apache-client', version: '+'
latestDepTestCompile group: 'software.amazon.awssdk', name: 's3', version: '+'
latestDepTestCompile group: 'software.amazon.awssdk', name: 'rds', version: '+'
latestDepTestCompile group: 'software.amazon.awssdk', name: 'ec2', version: '+'
+ latestDepTestCompile group: 'software.amazon.awssdk', name: 'sqs', version: '+'
+ latestDepTestCompile group: 'software.amazon.awssdk', name: 'dynamodb', version: '+'
+ latestDepTestCompile group: 'software.amazon.awssdk', name: 'kinesis', version: '+'
}

MODIFY
dd-java-agent/instrumentation/aws-java-sdk-2.2/src/main/java8/datadog/trace/instrumentation/aws/v2/AwsSdkClientDecorator.java
dd-java-agent/instrumentation/aws-java-sdk-2.2/src/main/java8/datadog/trace/instrumentation/aws/v2/AwsSdkClientDecorator.java
@@ -5,6 +5,7 @@ import datadog.trace.api.DDTags;
import io.opentracing.Span;
import java.net.URI;
import software.amazon.awssdk.awscore.AwsResponse;
+import software.amazon.awssdk.core.SdkRequest;
import software.amazon.awssdk.core.SdkResponse;
import software.amazon.awssdk.core.interceptor.ExecutionAttributes;
import software.amazon.awssdk.core.interceptor.SdkExecutionAttribute;
@@ -16,6 +17,29 @@ public class AwsSdkClientDecorator extends HttpClientDecorator<SdkHttpRequest, S
static final String COMPONENT_NAME = "java-aws-sdk";
+ public Span onSdkRequest(final Span span, final SdkRequest request) {
+ // S3
+ request
+ .getValueForField("Bucket", String.class)
+ .ifPresent(name -> span.setTag("aws.bucket.name", name));
+ // DynamoDB
+ request
+ .getValueForField("TableName", String.class)
+ .ifPresent(name -> span.setTag("aws.table.name", name));
+ // SQS
+ request
+ .getValueForField("QueueName", String.class)
+ .ifPresent(name -> span.setTag("aws.queue.name", name));
+ request
+ .getValueForField("QueueUrl", String.class)
+ .ifPresent(name -> span.setTag("aws.queue.url", name));
+ // Kinesis
+ request
+ .getValueForField("StreamName", String.class)
+ .ifPresent(name -> span.setTag("aws.stream.name", name));
+ return span;
+ }
+
public Span onAttributes(final Span span, final ExecutionAttributes attributes) {
final String awsServiceName = attributes.getAttribute(SdkExecutionAttribute.SERVICE_NAME);

MODIFY
dd-java-agent/instrumentation/aws-java-sdk-2.2/src/main/java8/datadog/trace/instrumentation/aws/v2/TracingExecutionInterceptor.java
dd-java-agent/instrumentation/aws-java-sdk-2.2/src/main/java8/datadog/trace/instrumentation/aws/v2/TracingExecutionInterceptor.java
@@ -44,9 +44,9 @@ public class TracingExecutionInterceptor implements ExecutionInterceptor {
public void afterMarshalling(
final Context.AfterMarshalling context, final ExecutionAttributes executionAttributes) {
final Span span = executionAttributes.getAttribute(SPAN_ATTRIBUTE);
- final SdkHttpRequest httpRequest = context.httpRequest();
- DECORATE.onRequest(span, httpRequest);
+ DECORATE.onRequest(span, context.httpRequest());
+ DECORATE.onSdkRequest(span, context.request());
DECORATE.onAttributes(span, executionAttributes);
}

MODIFY
dd-java-agent/instrumentation/aws-java-sdk-2.2/src/test/groovy/AwsClientTest.groovy
dd-java-agent/instrumentation/aws-java-sdk-2.2/src/test/groovy/AwsClientTest.groovy
@@ -3,12 +3,18 @@ import datadog.trace.api.DDSpanTypes
import io.opentracing.tag.Tags
import software.amazon.awssdk.auth.credentials.AwsBasicCredentials
import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider
+import software.amazon.awssdk.core.ResponseInputStream
import software.amazon.awssdk.core.async.AsyncResponseTransformer
import software.amazon.awssdk.core.exception.SdkClientException
import software.amazon.awssdk.http.apache.ApacheHttpClient
import software.amazon.awssdk.regions.Region
+import software.amazon.awssdk.services.dynamodb.DynamoDbAsyncClient
+import software.amazon.awssdk.services.dynamodb.DynamoDbClient
+import software.amazon.awssdk.services.dynamodb.model.CreateTableRequest
import software.amazon.awssdk.services.ec2.Ec2AsyncClient
import software.amazon.awssdk.services.ec2.Ec2Client
+import software.amazon.awssdk.services.kinesis.KinesisClient
+import software.amazon.awssdk.services.kinesis.model.DeleteStreamRequest
import software.amazon.awssdk.services.rds.RdsAsyncClient
import software.amazon.awssdk.services.rds.RdsClient
import software.amazon.awssdk.services.rds.model.DeleteOptionGroupRequest
@@ -16,6 +22,10 @@ import software.amazon.awssdk.services.s3.S3AsyncClient
import software.amazon.awssdk.services.s3.S3Client
import software.amazon.awssdk.services.s3.model.CreateBucketRequest
import software.amazon.awssdk.services.s3.model.GetObjectRequest
+import software.amazon.awssdk.services.sqs.SqsAsyncClient
+import software.amazon.awssdk.services.sqs.SqsClient
+import software.amazon.awssdk.services.sqs.model.CreateQueueRequest
+import software.amazon.awssdk.services.sqs.model.SendMessageRequest
import spock.lang.AutoCleanup
import spock.lang.Shared
@@ -59,6 +69,7 @@ class AwsClientTest extends AgentTestRunner {
expect:
response != null
+ response.class.simpleName.startsWith(operation) || response instanceof ResponseInputStream
assertTraces(1) {
trace(0, 2) {
@@ -81,6 +92,17 @@ class AwsClientTest extends AgentTestRunner {
"aws.operation" "${operation}"
"aws.agent" "java-aws-sdk"
"aws.requestId" "$requestId"
+ if (service == "S3") {
+ "aws.bucket.name" "somebucket"
+ } else if (service == "Sqs" && operation == "CreateQueue") {
+ "aws.queue.name" "somequeue"
+ } else if (service == "Sqs" && operation == "SendMessage") {
+ "aws.queue.url" "someurl"
+ } else if (service == "DynamoDb") {
+ "aws.table.name" "sometable"
+ } else if (service == "Kinesis") {
+ "aws.stream.name" "somestream"
+ }
defaultTags()
}
}
@@ -107,23 +129,39 @@ class AwsClientTest extends AgentTestRunner {
server.lastRequest.headers.get("x-datadog-parent-id") == null
where:
- service | operation | method | path | requestId | call | body | builder
- "S3" | "CreateBucket" | "PUT" | "/testbucket" | "UNKNOWN" | { c -> c.createBucket(CreateBucketRequest.builder().bucket("testbucket").build()) } | "" | S3Client.builder()
- "S3" | "GetObject" | "GET" | "/someBucket/someKey" | "UNKNOWN" | { c -> c.getObject(GetObjectRequest.builder().bucket("someBucket").key("someKey").build()) } | "" | S3Client.builder()
- "Ec2" | "AllocateAddress" | "POST" | "/" | "59dbff89-35bd-4eac-99ed-be587EXAMPLE" | { c -> c.allocateAddress() } | """
+ service | operation | method | path | requestId | builder | call | body
+ "S3" | "CreateBucket" | "PUT" | "/somebucket" | "UNKNOWN" | S3Client.builder() | { c -> c.createBucket(CreateBucketRequest.builder().bucket("somebucket").build()) } | ""
+ "S3" | "GetObject" | "GET" | "/somebucket/somekey" | "UNKNOWN" | S3Client.builder() | { c -> c.getObject(GetObjectRequest.builder().bucket("somebucket").key("somekey").build()) } | ""
+ "DynamoDb" | "CreateTable" | "POST" | "/" | "UNKNOWN" | DynamoDbClient.builder() | { c -> c.createTable(CreateTableRequest.builder().tableName("sometable").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()) } | """
+ <SendMessageResponse>
+ <SendMessageResult>
+ <MD5OfMessageBody>d41d8cd98f00b204e9800998ecf8427e</MD5OfMessageBody>
+ <MD5OfMessageAttributes>3ae8f24a165a8cedc005670c81a27295</MD5OfMessageAttributes>
+ <MessageId>5fea7756-0ea4-451a-a703-a558b933e274</MessageId>
+ </SendMessageResult>
+ <ResponseMetadata><RequestId>27daac76-34dd-47df-bd01-1f6e873584a0</RequestId></ResponseMetadata>
+ </SendMessageResponse>
+ """
+ "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>
- """ | Ec2Client.builder()
- "Rds" | "DeleteOptionGroup" | "POST" | "/" | "0ac9cda2-bbf4-11d3-f92b-31fa5e8dbc99" | { 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>
+ <ResponseMetadata><RequestId>0ac9cda2-bbf4-11d3-f92b-31fa5e8dbc99</RequestId></ResponseMetadata>
</DeleteOptionGroupResponse>
- """ | RdsClient.builder()
+ """
}
def "send #operation async request with builder {#builder.class.getName()} mocked response"() {
@@ -171,6 +209,17 @@ class AwsClientTest extends AgentTestRunner {
"aws.operation" "${operation}"
"aws.agent" "java-aws-sdk"
"aws.requestId" "$requestId"
+ if (service == "S3") {
+ "aws.bucket.name" "somebucket"
+ } else if (service == "Sqs" && operation == "CreateQueue") {
+ "aws.queue.name" "somequeue"
+ } else if (service == "Sqs" && operation == "SendMessage") {
+ "aws.queue.url" "someurl"
+ } else if (service == "DynamoDb") {
+ "aws.table.name" "sometable"
+ } else if (service == "Kinesis") {
+ "aws.stream.name" "somestream"
+ }
defaultTags()
}
}
@@ -201,23 +250,40 @@ class AwsClientTest extends AgentTestRunner {
server.lastRequest.headers.get("x-datadog-parent-id") == null
where:
- service | operation | method | path | requestId | call | body | builder
- "S3" | "CreateBucket" | "PUT" | "/testbucket" | "UNKNOWN" | { c -> c.createBucket(CreateBucketRequest.builder().bucket("testbucket").build()) } | "" | S3AsyncClient.builder()
- "S3" | "GetObject" | "GET" | "/someBucket/someKey" | "UNKNOWN" | { c -> c.getObject(GetObjectRequest.builder().bucket("someBucket").key("someKey").build(), AsyncResponseTransformer.toBytes()) } | "1234567890" | S3AsyncClient.builder()
- "Ec2" | "AllocateAddress" | "POST" | "/" | "59dbff89-35bd-4eac-99ed-be587EXAMPLE" | { c -> c.allocateAddress() } | """
+ service | operation | method | path | requestId | builder | call | body
+ "S3" | "CreateBucket" | "PUT" | "/somebucket" | "UNKNOWN" | S3AsyncClient.builder() | { c -> c.createBucket(CreateBucketRequest.builder().bucket("somebucket").build()) } | ""
+ "S3" | "GetObject" | "GET" | "/somebucket/somekey" | "UNKNOWN" | S3AsyncClient.builder() | { c -> c.getObject(GetObjectRequest.builder().bucket("somebucket").key("somekey").build(), AsyncResponseTransformer.toBytes()) } | "1234567890"
+ "DynamoDb" | "CreateTable" | "POST" | "/" | "UNKNOWN" | DynamoDbAsyncClient.builder() | { c -> c.createTable(CreateTableRequest.builder().tableName("sometable").build()) } | ""
+ // 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()) } | """
+ <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()) } | """
+ <SendMessageResponse>
+ <SendMessageResult>
+ <MD5OfMessageBody>d41d8cd98f00b204e9800998ecf8427e</MD5OfMessageBody>
+ <MD5OfMessageAttributes>3ae8f24a165a8cedc005670c81a27295</MD5OfMessageAttributes>
+ <MessageId>5fea7756-0ea4-451a-a703-a558b933e274</MessageId>
+ </SendMessageResult>
+ <ResponseMetadata><RequestId>27daac76-34dd-47df-bd01-1f6e873584a0</RequestId></ResponseMetadata>
+ </SendMessageResponse>
+ """
+ "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>
- """ | Ec2AsyncClient.builder()
- "Rds" | "DeleteOptionGroup" | "POST" | "/" | "0ac9cda2-bbf4-11d3-f92b-31fa5e8dbc99" | { 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>
+ <ResponseMetadata><RequestId>0ac9cda2-bbf4-11d3-f92b-31fa5e8dbc99</RequestId></ResponseMetadata>
</DeleteOptionGroupResponse>
- """ | RdsAsyncClient.builder()
+ """
}
def "timeout and retry errors captured"() {
@@ -238,7 +304,7 @@ class AwsClientTest extends AgentTestRunner {
.build()
when:
- client.getObject(GetObjectRequest.builder().bucket("someBucket").key("someKey").build())
+ client.getObject(GetObjectRequest.builder().bucket("somebucket").key("somekey").build())
then:
thrown SdkClientException
@@ -254,7 +320,7 @@ class AwsClientTest extends AgentTestRunner {
parent()
tags {
"$Tags.COMPONENT.key" "java-aws-sdk"
- "$Tags.HTTP_URL.key" "$server.address/someBucket/someKey"
+ "$Tags.HTTP_URL.key" "$server.address/somebucket/somekey"
"$Tags.HTTP_METHOD.key" "GET"
"$Tags.PEER_HOSTNAME.key" "localhost"
"$Tags.PEER_PORT.key" server.address.port
@@ -262,6 +328,7 @@ class AwsClientTest extends AgentTestRunner {
"aws.service" "S3"
"aws.operation" "GetObject"
"aws.agent" "java-aws-sdk"
+ "aws.bucket.name" "somebucket"
errorTags SdkClientException, "Unable to execute HTTP request: Read timed out"
defaultTags()
}
@@ -269,13 +336,13 @@ class AwsClientTest extends AgentTestRunner {
(1..4).each {
span(it) {
operationName "http.request"
- resourceName "GET /someBucket/someKey"
+ resourceName "GET /somebucket/somekey"
spanType DDSpanTypes.HTTP_CLIENT
errored true
childOf(span(0))
tags {
"$Tags.COMPONENT.key" "apache-httpclient"
- "$Tags.HTTP_URL.key" "$server.address/someBucket/someKey"
+ "$Tags.HTTP_URL.key" "$server.address/somebucket/somekey"
"$Tags.PEER_HOSTNAME.key" "localhost"
"$Tags.PEER_PORT.key" server.address.port
"$Tags.HTTP_METHOD.key" "GET"

Add additional tags for aws-sdk spans

s3 -> bucket name
dynamodb -> table name
sqs -> queue name/url
kinesis -> stream name