From 4947dc3bd31c53d45a69e2c9f48f0c58b9a0ce84 Mon Sep 17 00:00:00 2001 From: Tyler Benson Date: Thu, 2 Jan 2020 11:35:21 -0800 Subject: [PATCH] Add various tags for AWS SDK v1.x This brings it inline with the v2 instrumentation. --- .../aws-java-sdk-1.11.0.gradle | 19 +++ .../aws/v0/AWSClientInstrumentation.java | 12 +- .../aws/v0/AWSHttpClientInstrumentation.java | 18 +-- .../aws/v0/AwsSdkClientDecorator.java | 23 ++- .../aws/v0/OnErrorDecorator.java | 22 +++ .../aws/v0/RequestInstrumentation.java | 144 ++++++++++++++++++ .../instrumentation/aws/v0/RequestMeta.java | 19 +++ .../aws/v0/TracingRequestHandler.java | 27 ++-- .../src/test/groovy/AWSClientTest.groovy | 64 ++++++-- .../groovy/AWSClientTest.groovy | 30 ++-- .../aws/v2/AwsSdkClientDecorator.java | 14 +- 11 files changed, 332 insertions(+), 60 deletions(-) create mode 100644 dd-java-agent/instrumentation/aws-java-sdk-1.11.0/src/main/java/datadog/trace/instrumentation/aws/v0/OnErrorDecorator.java create mode 100644 dd-java-agent/instrumentation/aws-java-sdk-1.11.0/src/main/java/datadog/trace/instrumentation/aws/v0/RequestInstrumentation.java create mode 100644 dd-java-agent/instrumentation/aws-java-sdk-1.11.0/src/main/java/datadog/trace/instrumentation/aws/v0/RequestMeta.java diff --git a/dd-java-agent/instrumentation/aws-java-sdk-1.11.0/aws-java-sdk-1.11.0.gradle b/dd-java-agent/instrumentation/aws-java-sdk-1.11.0/aws-java-sdk-1.11.0.gradle index 9f99706cbd..5d1758d60f 100644 --- a/dd-java-agent/instrumentation/aws-java-sdk-1.11.0/aws-java-sdk-1.11.0.gradle +++ b/dd-java-agent/instrumentation/aws-java-sdk-1.11.0/aws-java-sdk-1.11.0.gradle @@ -39,9 +39,16 @@ dependencies { // Include httpclient instrumentation for testing because it is a dependency for aws-sdk. testCompile project(':dd-java-agent:instrumentation:apache-httpclient-4') + testCompile group: 'com.amazonaws', name: 'aws-java-sdk-s3', version: '1.11.106' testCompile group: 'com.amazonaws', name: 'aws-java-sdk-rds', version: '1.11.106' testCompile group: 'com.amazonaws', name: 'aws-java-sdk-ec2', version: '1.11.106' + testCompile group: 'com.amazonaws', name: 'aws-java-sdk-kinesis', version: '1.11.106' + testCompile group: 'com.amazonaws', name: 'aws-java-sdk-sqs', version: '1.11.106' + testCompile group: 'com.amazonaws', name: 'aws-java-sdk-dynamodb', version: '1.11.106' + + // needed for kinesis: + testCompile group: 'com.fasterxml.jackson.dataformat', name: 'jackson-dataformat-cbor', version: versions.jackson test_before_1_11_106Compile(group: 'com.amazonaws', name: 'aws-java-sdk-s3', version: '1.11.0') { force = true @@ -52,10 +59,22 @@ dependencies { test_before_1_11_106Compile(group: 'com.amazonaws', name: 'aws-java-sdk-ec2', version: '1.11.0') { force = true } + test_before_1_11_106Compile(group: 'com.amazonaws', name: 'aws-java-sdk-kinesis', version: '1.11.0') { + force = true + } + test_before_1_11_106Compile(group: 'com.amazonaws', name: 'aws-java-sdk-sqs', version: '1.11.0') { + force = true + } + test_before_1_11_106Compile(group: 'com.amazonaws', name: 'aws-java-sdk-dynamodb', version: '1.11.0') { + force = true + } latestDepTestCompile group: 'com.amazonaws', name: 'aws-java-sdk-s3', version: '+' latestDepTestCompile group: 'com.amazonaws', name: 'aws-java-sdk-rds', version: '+' latestDepTestCompile group: 'com.amazonaws', name: 'aws-java-sdk-ec2', version: '+' + latestDepTestCompile group: 'com.amazonaws', name: 'aws-java-sdk-kinesis', version: '+' + latestDepTestCompile group: 'com.amazonaws', name: 'aws-java-sdk-sqs', version: '+' + latestDepTestCompile group: 'com.amazonaws', name: 'aws-java-sdk-dynamodb', version: '+' } test.dependsOn test_before_1_11_106 diff --git a/dd-java-agent/instrumentation/aws-java-sdk-1.11.0/src/main/java/datadog/trace/instrumentation/aws/v0/AWSClientInstrumentation.java b/dd-java-agent/instrumentation/aws-java-sdk-1.11.0/src/main/java/datadog/trace/instrumentation/aws/v0/AWSClientInstrumentation.java index 149737ad04..a23c1f0966 100644 --- a/dd-java-agent/instrumentation/aws-java-sdk-1.11.0/src/main/java/datadog/trace/instrumentation/aws/v0/AWSClientInstrumentation.java +++ b/dd-java-agent/instrumentation/aws-java-sdk-1.11.0/src/main/java/datadog/trace/instrumentation/aws/v0/AWSClientInstrumentation.java @@ -5,9 +5,11 @@ import static net.bytebuddy.matcher.ElementMatchers.declaresField; import static net.bytebuddy.matcher.ElementMatchers.isConstructor; import static net.bytebuddy.matcher.ElementMatchers.named; +import com.amazonaws.AmazonWebServiceRequest; import com.amazonaws.handlers.RequestHandler2; import com.google.auto.service.AutoService; import datadog.trace.agent.tooling.Instrumenter; +import datadog.trace.bootstrap.InstrumentationContext; import java.util.List; import java.util.Map; import net.bytebuddy.asm.Advice; @@ -39,6 +41,7 @@ public final class AWSClientInstrumentation extends Instrumenter.Default { "datadog.trace.agent.decorator.ClientDecorator", "datadog.trace.agent.decorator.HttpClientDecorator", packageName + ".AwsSdkClientDecorator", + packageName + ".RequestMeta", packageName + ".TracingRequestHandler", }; } @@ -49,6 +52,11 @@ public final class AWSClientInstrumentation extends Instrumenter.Default { isConstructor(), AWSClientInstrumentation.class.getName() + "$AWSClientAdvice"); } + @Override + public Map contextStore() { + return singletonMap("com.amazonaws.AmazonWebServiceRequest", packageName + ".RequestMeta"); + } + public static class AWSClientAdvice { // Since we're instrumenting the constructor, we can't add onThrowable. @Advice.OnMethodExit(suppress = Throwable.class) @@ -62,7 +70,9 @@ public final class AWSClientInstrumentation extends Instrumenter.Default { } } if (!hasDDHandler) { - handlers.add(TracingRequestHandler.INSTANCE); + handlers.add( + new TracingRequestHandler( + InstrumentationContext.get(AmazonWebServiceRequest.class, RequestMeta.class))); } } } diff --git a/dd-java-agent/instrumentation/aws-java-sdk-1.11.0/src/main/java/datadog/trace/instrumentation/aws/v0/AWSHttpClientInstrumentation.java b/dd-java-agent/instrumentation/aws-java-sdk-1.11.0/src/main/java/datadog/trace/instrumentation/aws/v0/AWSHttpClientInstrumentation.java index da23fafaf7..04ff1dfdef 100644 --- a/dd-java-agent/instrumentation/aws-java-sdk-1.11.0/src/main/java/datadog/trace/instrumentation/aws/v0/AWSHttpClientInstrumentation.java +++ b/dd-java-agent/instrumentation/aws-java-sdk-1.11.0/src/main/java/datadog/trace/instrumentation/aws/v0/AWSHttpClientInstrumentation.java @@ -1,6 +1,7 @@ package datadog.trace.instrumentation.aws.v0; -import static datadog.trace.instrumentation.aws.v0.AwsSdkClientDecorator.DECORATE; +import static datadog.trace.instrumentation.aws.v0.OnErrorDecorator.DECORATE; +import static datadog.trace.instrumentation.aws.v0.RequestMeta.SCOPE_CONTEXT_KEY; import static java.util.Collections.singletonMap; import static net.bytebuddy.matcher.ElementMatchers.isAbstract; import static net.bytebuddy.matcher.ElementMatchers.isMethod; @@ -40,10 +41,8 @@ public class AWSHttpClientInstrumentation extends Instrumenter.Default { public String[] helperClassNames() { return new String[] { "datadog.trace.agent.decorator.BaseDecorator", - "datadog.trace.agent.decorator.ClientDecorator", - "datadog.trace.agent.decorator.HttpClientDecorator", - packageName + ".AwsSdkClientDecorator", - packageName + ".TracingRequestHandler", + packageName + ".OnErrorDecorator", + packageName + ".RequestMeta", }; } @@ -60,9 +59,9 @@ public class AWSHttpClientInstrumentation extends Instrumenter.Default { @Advice.Argument(value = 0, optional = true) final Request request, @Advice.Thrown final Throwable throwable) { if (throwable != null) { - final AgentScope scope = request.getHandlerContext(TracingRequestHandler.SCOPE_CONTEXT_KEY); + final AgentScope scope = request.getHandlerContext(SCOPE_CONTEXT_KEY); if (scope != null) { - request.addHandlerContext(TracingRequestHandler.SCOPE_CONTEXT_KEY, null); + request.addHandlerContext(SCOPE_CONTEXT_KEY, null); DECORATE.onError(scope.span(), throwable); DECORATE.beforeFinish(scope.span()); scope.close(); @@ -96,10 +95,9 @@ public class AWSHttpClientInstrumentation extends Instrumenter.Default { @Advice.FieldValue("request") final Request request, @Advice.Thrown final Throwable throwable) { if (throwable != null) { - final AgentScope scope = - request.getHandlerContext(TracingRequestHandler.SCOPE_CONTEXT_KEY); + final AgentScope scope = request.getHandlerContext(SCOPE_CONTEXT_KEY); if (scope != null) { - request.addHandlerContext(TracingRequestHandler.SCOPE_CONTEXT_KEY, null); + request.addHandlerContext(SCOPE_CONTEXT_KEY, null); DECORATE.onError(scope.span(), throwable); DECORATE.beforeFinish(scope.span()); scope.close(); diff --git a/dd-java-agent/instrumentation/aws-java-sdk-1.11.0/src/main/java/datadog/trace/instrumentation/aws/v0/AwsSdkClientDecorator.java b/dd-java-agent/instrumentation/aws-java-sdk-1.11.0/src/main/java/datadog/trace/instrumentation/aws/v0/AwsSdkClientDecorator.java index 8f743eb49e..a845cfee6a 100644 --- a/dd-java-agent/instrumentation/aws-java-sdk-1.11.0/src/main/java/datadog/trace/instrumentation/aws/v0/AwsSdkClientDecorator.java +++ b/dd-java-agent/instrumentation/aws-java-sdk-1.11.0/src/main/java/datadog/trace/instrumentation/aws/v0/AwsSdkClientDecorator.java @@ -1,10 +1,12 @@ package datadog.trace.instrumentation.aws.v0; +import com.amazonaws.AmazonWebServiceRequest; import com.amazonaws.AmazonWebServiceResponse; import com.amazonaws.Request; import com.amazonaws.Response; import datadog.trace.agent.decorator.HttpClientDecorator; import datadog.trace.api.DDTags; +import datadog.trace.bootstrap.ContextStore; import datadog.trace.instrumentation.api.AgentSpan; import java.net.URI; import java.net.URISyntaxException; @@ -12,12 +14,17 @@ import java.util.Map; import java.util.concurrent.ConcurrentHashMap; public class AwsSdkClientDecorator extends HttpClientDecorator { - public static final AwsSdkClientDecorator DECORATE = new AwsSdkClientDecorator(); static final String COMPONENT_NAME = "java-aws-sdk"; private final Map serviceNames = new ConcurrentHashMap<>(); private final Map operationNames = new ConcurrentHashMap<>(); + private final ContextStore contextStore; + + public AwsSdkClientDecorator( + final ContextStore contextStore) { + this.contextStore = contextStore; + } @Override public AgentSpan onRequest(final AgentSpan span, final Request request) { @@ -25,7 +32,8 @@ public class AwsSdkClientDecorator extends HttpClientDecorator awsOperation = request.getOriginalRequest().getClass(); + final AmazonWebServiceRequest originalRequest = request.getOriginalRequest(); + final Class awsOperation = originalRequest.getClass(); span.setTag("aws.agent", COMPONENT_NAME); span.setTag("aws.service", awsServiceName); @@ -36,6 +44,17 @@ public class AwsSdkClientDecorator extends HttpClientDecorator typeMatcher() { + return safeHasSuperType(named("com.amazonaws.AmazonWebServiceRequest")); + } + + @Override + public String[] helperClassNames() { + return new String[] { + packageName + ".RequestMeta", + }; + } + + @Override + public Map, String> transformers() { + final Map, String> transformers = new HashMap<>(); + transformers.put( + named("setBucketName").and(takesArgument(0, String.class)), + RequestInstrumentation.class.getName() + "$BucketNameAdvice"); + transformers.put( + named("setQueueUrl").and(takesArgument(0, String.class)), + RequestInstrumentation.class.getName() + "$QueueUrlAdvice"); + transformers.put( + named("setQueueName").and(takesArgument(0, String.class)), + RequestInstrumentation.class.getName() + "$QueueNameAdvice"); + transformers.put( + named("setStreamName").and(takesArgument(0, String.class)), + RequestInstrumentation.class.getName() + "$StreamNameAdvice"); + transformers.put( + named("setTableName").and(takesArgument(0, String.class)), + RequestInstrumentation.class.getName() + "$TableNameAdvice"); + return transformers; + } + + @Override + public Map contextStore() { + return singletonMap("com.amazonaws.AmazonWebServiceRequest", packageName + ".RequestMeta"); + } + + public static class BucketNameAdvice { + @Advice.OnMethodEnter(suppress = Throwable.class) + public static void methodEnter( + @Advice.Argument(0) final String value, + @Advice.This final AmazonWebServiceRequest request) { + final ContextStore contextStore = + InstrumentationContext.get(AmazonWebServiceRequest.class, RequestMeta.class); + RequestMeta requestMeta = contextStore.get(request); + if (requestMeta == null) { + requestMeta = new RequestMeta(); + contextStore.put(request, requestMeta); + } + requestMeta.setBucketName(value); + } + } + + public static class QueueUrlAdvice { + @Advice.OnMethodEnter(suppress = Throwable.class) + public static void methodEnter( + @Advice.Argument(0) final String value, + @Advice.This final AmazonWebServiceRequest request) { + final ContextStore contextStore = + InstrumentationContext.get(AmazonWebServiceRequest.class, RequestMeta.class); + RequestMeta requestMeta = contextStore.get(request); + if (requestMeta == null) { + requestMeta = new RequestMeta(); + contextStore.put(request, requestMeta); + } + requestMeta.setQueueUrl(value); + } + } + + public static class QueueNameAdvice { + @Advice.OnMethodEnter(suppress = Throwable.class) + public static void methodEnter( + @Advice.Argument(0) final String value, + @Advice.This final AmazonWebServiceRequest request) { + final ContextStore contextStore = + InstrumentationContext.get(AmazonWebServiceRequest.class, RequestMeta.class); + RequestMeta requestMeta = contextStore.get(request); + if (requestMeta == null) { + requestMeta = new RequestMeta(); + contextStore.put(request, requestMeta); + } + requestMeta.setQueueName(value); + } + } + + public static class StreamNameAdvice { + @Advice.OnMethodEnter(suppress = Throwable.class) + public static void methodEnter( + @Advice.Argument(0) final String value, + @Advice.This final AmazonWebServiceRequest request) { + final ContextStore contextStore = + InstrumentationContext.get(AmazonWebServiceRequest.class, RequestMeta.class); + RequestMeta requestMeta = contextStore.get(request); + if (requestMeta == null) { + requestMeta = new RequestMeta(); + contextStore.put(request, requestMeta); + } + requestMeta.setStreamName(value); + } + } + + public static class TableNameAdvice { + @Advice.OnMethodEnter(suppress = Throwable.class) + public static void methodEnter( + @Advice.Argument(0) final String value, + @Advice.This final AmazonWebServiceRequest request) { + final ContextStore contextStore = + InstrumentationContext.get(AmazonWebServiceRequest.class, RequestMeta.class); + RequestMeta requestMeta = contextStore.get(request); + if (requestMeta == null) { + requestMeta = new RequestMeta(); + contextStore.put(request, requestMeta); + } + requestMeta.setTableName(value); + } + } +} diff --git a/dd-java-agent/instrumentation/aws-java-sdk-1.11.0/src/main/java/datadog/trace/instrumentation/aws/v0/RequestMeta.java b/dd-java-agent/instrumentation/aws-java-sdk-1.11.0/src/main/java/datadog/trace/instrumentation/aws/v0/RequestMeta.java new file mode 100644 index 0000000000..ef807e6240 --- /dev/null +++ b/dd-java-agent/instrumentation/aws-java-sdk-1.11.0/src/main/java/datadog/trace/instrumentation/aws/v0/RequestMeta.java @@ -0,0 +1,19 @@ +package datadog.trace.instrumentation.aws.v0; + +import com.amazonaws.handlers.HandlerContextKey; +import datadog.trace.instrumentation.api.AgentScope; +import lombok.Data; + +@Data +public class RequestMeta { + // Note: aws1.x sdk doesn't have any truly async clients so we can store scope in request context + // safely. + public static final HandlerContextKey SCOPE_CONTEXT_KEY = + new HandlerContextKey<>("DatadogScope"); + + private String bucketName; + private String queueUrl; + private String queueName; + private String streamName; + private String tableName; +} diff --git a/dd-java-agent/instrumentation/aws-java-sdk-1.11.0/src/main/java/datadog/trace/instrumentation/aws/v0/TracingRequestHandler.java b/dd-java-agent/instrumentation/aws-java-sdk-1.11.0/src/main/java/datadog/trace/instrumentation/aws/v0/TracingRequestHandler.java index 204e64810d..4639eb60e7 100644 --- a/dd-java-agent/instrumentation/aws-java-sdk-1.11.0/src/main/java/datadog/trace/instrumentation/aws/v0/TracingRequestHandler.java +++ b/dd-java-agent/instrumentation/aws-java-sdk-1.11.0/src/main/java/datadog/trace/instrumentation/aws/v0/TracingRequestHandler.java @@ -2,24 +2,25 @@ package datadog.trace.instrumentation.aws.v0; import static datadog.trace.instrumentation.api.AgentTracer.activateSpan; import static datadog.trace.instrumentation.api.AgentTracer.startSpan; -import static datadog.trace.instrumentation.aws.v0.AwsSdkClientDecorator.DECORATE; +import static datadog.trace.instrumentation.aws.v0.RequestMeta.SCOPE_CONTEXT_KEY; import com.amazonaws.AmazonWebServiceRequest; import com.amazonaws.Request; import com.amazonaws.Response; -import com.amazonaws.handlers.HandlerContextKey; import com.amazonaws.handlers.RequestHandler2; +import datadog.trace.bootstrap.ContextStore; import datadog.trace.instrumentation.api.AgentScope; import datadog.trace.instrumentation.api.AgentSpan; /** Tracing Request Handler */ public class TracingRequestHandler extends RequestHandler2 { - public static TracingRequestHandler INSTANCE = new TracingRequestHandler(); - // Note: aws1.x sdk doesn't have any truly async clients so we can store scope in request context - // safely. - public static final HandlerContextKey SCOPE_CONTEXT_KEY = - new HandlerContextKey<>("DatadogScope"); + private final AwsSdkClientDecorator decorate; + + public TracingRequestHandler( + final ContextStore contextStore) { + decorate = new AwsSdkClientDecorator(contextStore); + } @Override public AmazonWebServiceRequest beforeMarshalling(final AmazonWebServiceRequest request) { @@ -29,8 +30,8 @@ public class TracingRequestHandler extends RequestHandler2 { @Override public void beforeRequest(final Request request) { final AgentSpan span = startSpan("aws.command"); - DECORATE.afterStart(span); - DECORATE.onRequest(span, request); + decorate.afterStart(span); + decorate.onRequest(span, request); request.addHandlerContext(SCOPE_CONTEXT_KEY, activateSpan(span, true)); } @@ -39,8 +40,8 @@ public class TracingRequestHandler extends RequestHandler2 { final AgentScope scope = request.getHandlerContext(SCOPE_CONTEXT_KEY); if (scope != null) { request.addHandlerContext(SCOPE_CONTEXT_KEY, null); - DECORATE.onResponse(scope.span(), response); - DECORATE.beforeFinish(scope.span()); + decorate.onResponse(scope.span(), response); + decorate.beforeFinish(scope.span()); scope.close(); } } @@ -50,8 +51,8 @@ public class TracingRequestHandler extends RequestHandler2 { final AgentScope scope = request.getHandlerContext(SCOPE_CONTEXT_KEY); if (scope != null) { request.addHandlerContext(SCOPE_CONTEXT_KEY, null); - DECORATE.onError(scope.span(), e); - DECORATE.beforeFinish(scope.span()); + decorate.onError(scope.span(), e); + decorate.beforeFinish(scope.span()); scope.close(); } } diff --git a/dd-java-agent/instrumentation/aws-java-sdk-1.11.0/src/test/groovy/AWSClientTest.groovy b/dd-java-agent/instrumentation/aws-java-sdk-1.11.0/src/test/groovy/AWSClientTest.groovy index af10ce4e00..1e526774ab 100644 --- a/dd-java-agent/instrumentation/aws-java-sdk-1.11.0/src/test/groovy/AWSClientTest.groovy +++ b/dd-java-agent/instrumentation/aws-java-sdk-1.11.0/src/test/groovy/AWSClientTest.groovy @@ -16,11 +16,18 @@ import com.amazonaws.client.builder.AwsClientBuilder import com.amazonaws.handlers.RequestHandler2 import com.amazonaws.regions.Regions import com.amazonaws.retry.PredefinedRetryPolicies +import com.amazonaws.services.dynamodbv2.AmazonDynamoDBClientBuilder +import com.amazonaws.services.dynamodbv2.model.CreateTableRequest import com.amazonaws.services.ec2.AmazonEC2ClientBuilder +import com.amazonaws.services.kinesis.AmazonKinesisClientBuilder +import com.amazonaws.services.kinesis.model.DeleteStreamRequest import com.amazonaws.services.rds.AmazonRDSClientBuilder import com.amazonaws.services.rds.model.DeleteOptionGroupRequest import com.amazonaws.services.s3.AmazonS3Client import com.amazonaws.services.s3.AmazonS3ClientBuilder +import com.amazonaws.services.sqs.AmazonSQSClientBuilder +import com.amazonaws.services.sqs.model.CreateQueueRequest +import com.amazonaws.services.sqs.model.SendMessageRequest import datadog.trace.agent.test.AgentTestRunner import datadog.trace.api.DDSpanTypes import datadog.trace.instrumentation.api.Tags @@ -143,12 +150,15 @@ class AWSClientTest extends AgentTestRunner { "aws.endpoint" "$server.address" "aws.operation" "${operation}Request" "aws.agent" "java-aws-sdk" + for (def addedTag : additionalTags) { + "$addedTag.key" "$addedTag.value" + } defaultTags() } } span(1) { operationName "http.request" - resourceName "$method /$url" + resourceName "$method $path" spanType DDSpanTypes.HTTP_CLIENT errored false childOf(span(0)) @@ -157,7 +167,7 @@ class AWSClientTest extends AgentTestRunner { "$Tags.SPAN_KIND" Tags.SPAN_KIND_CLIENT "$Tags.PEER_HOSTNAME" "localhost" "$Tags.PEER_PORT" server.address.port - "$Tags.HTTP_URL" "$server.address/$url" + "$Tags.HTTP_URL" "${server.address}${path}" "$Tags.HTTP_METHOD" "$method" "$Tags.HTTP_STATUS" 200 defaultTags() @@ -169,23 +179,41 @@ class AWSClientTest extends AgentTestRunner { server.lastRequest.headers.get("x-datadog-parent-id") == null where: - service | operation | method | url | handlerCount | call | body | client - "S3" | "CreateBucket" | "PUT" | "testbucket/" | 1 | { client -> client.createBucket("testbucket") } | "" | AmazonS3ClientBuilder.standard().withPathStyleAccessEnabled(true).withEndpointConfiguration(endpoint).withCredentials(credentialsProvider).build() - "S3" | "GetObject" | "GET" | "someBucket/someKey" | 1 | { client -> client.getObject("someBucket", "someKey") } | "" | AmazonS3ClientBuilder.standard().withPathStyleAccessEnabled(true).withEndpointConfiguration(endpoint).withCredentials(credentialsProvider).build() - "EC2" | "AllocateAddress" | "POST" | "" | 4 | { client -> client.allocateAddress() } | """ - - 59dbff89-35bd-4eac-99ed-be587EXAMPLE - 192.0.2.1 - standard - - """ | AmazonEC2ClientBuilder.standard().withEndpointConfiguration(endpoint).withCredentials(credentialsProvider).build() - "RDS" | "DeleteOptionGroup" | "POST" | "" | 5 | { client -> client.deleteOptionGroup(new DeleteOptionGroupRequest()) } | """ + service | operation | method | path | handlerCount | client | call | additionalTags | body + "S3" | "CreateBucket" | "PUT" | "/testbucket/" | 1 | AmazonS3ClientBuilder.standard().withPathStyleAccessEnabled(true).withEndpointConfiguration(endpoint).withCredentials(credentialsProvider).build() | { client -> client.createBucket("testbucket") } | ["aws.bucket.name": "testbucket"] | "" + "S3" | "GetObject" | "GET" | "/someBucket/someKey" | 1 | AmazonS3ClientBuilder.standard().withPathStyleAccessEnabled(true).withEndpointConfiguration(endpoint).withCredentials(credentialsProvider).build() | { client -> client.getObject("someBucket", "someKey") } | ["aws.bucket.name": "someBucket"] | "" + "DynamoDBv2" | "CreateTable" | "POST" | "/" | 1 | AmazonDynamoDBClientBuilder.standard().withEndpointConfiguration(endpoint).withCredentials(credentialsProvider).build() | { c -> c.createTable(new CreateTableRequest("sometable", null)) } | ["aws.table.name": "sometable"] | "" + "Kinesis" | "DeleteStream" | "POST" | "/" | 1 | AmazonKinesisClientBuilder.standard().withEndpointConfiguration(endpoint).withCredentials(credentialsProvider).build() | { c -> c.deleteStream(new DeleteStreamRequest().withStreamName("somestream")) } | ["aws.stream.name": "somestream"] | "" + "SQS" | "CreateQueue" | "POST" | "/" | 4 | AmazonSQSClientBuilder.standard().withEndpointConfiguration(endpoint).withCredentials(credentialsProvider).build() | { c -> c.createQueue(new CreateQueueRequest("somequeue")) } | ["aws.queue.name": "somequeue"] | """ + + https://queue.amazonaws.com/123456789012/MyQueue + 7a62c49f-347e-4fc4-9331-6e8e7a96aa73 + + """ + "SQS" | "SendMessage" | "POST" | "/someurl" | 4 | AmazonSQSClientBuilder.standard().withEndpointConfiguration(endpoint).withCredentials(credentialsProvider).build() | { c -> c.sendMessage(new SendMessageRequest("someurl", "")) } | ["aws.queue.url": "someurl"] | """ + + + d41d8cd98f00b204e9800998ecf8427e + 3ae8f24a165a8cedc005670c81a27295 + 5fea7756-0ea4-451a-a703-a558b933e274 + + 27daac76-34dd-47df-bd01-1f6e873584a0 + + """ + "EC2" | "AllocateAddress" | "POST" | "/" | 4 | AmazonEC2ClientBuilder.standard().withEndpointConfiguration(endpoint).withCredentials(credentialsProvider).build() | { client -> client.allocateAddress() } | [:] | """ + + 59dbff89-35bd-4eac-99ed-be587EXAMPLE + 192.0.2.1 + standard + + """ + "RDS" | "DeleteOptionGroup" | "POST" | "/" | 5 | AmazonRDSClientBuilder.standard().withEndpointConfiguration(endpoint).withCredentials(credentialsProvider).build() | { client -> client.deleteOptionGroup(new DeleteOptionGroupRequest()) } | [:] | """ 0ac9cda2-bbf4-11d3-f92b-31fa5e8dbc99 - """ | AmazonRDSClientBuilder.standard().withEndpointConfiguration(endpoint).withCredentials(credentialsProvider).build() + """ } def "send #operation request to closed port"() { @@ -216,6 +244,9 @@ class AWSClientTest extends AgentTestRunner { "aws.endpoint" "http://localhost:${UNUSABLE_PORT}" "aws.operation" "${operation}Request" "aws.agent" "java-aws-sdk" + for (def addedTag : additionalTags) { + "$addedTag.key" "$addedTag.value" + } errorTags SdkClientException, ~/Unable to execute HTTP request/ defaultTags() } @@ -241,8 +272,8 @@ class AWSClientTest extends AgentTestRunner { } where: - service | operation | method | url | call | body | client - "S3" | "GetObject" | "GET" | "someBucket/someKey" | { client -> client.getObject("someBucket", "someKey") } | "" | new AmazonS3Client(CREDENTIALS_PROVIDER_CHAIN, new ClientConfiguration().withRetryPolicy(PredefinedRetryPolicies.getDefaultRetryPolicyWithCustomMaxRetries(0))).withEndpoint("http://localhost:${UNUSABLE_PORT}") + service | operation | method | url | call | additionalTags | body | client + "S3" | "GetObject" | "GET" | "someBucket/someKey" | { client -> client.getObject("someBucket", "someKey") } | ["aws.bucket.name": "someBucket"] | "" | new AmazonS3Client(CREDENTIALS_PROVIDER_CHAIN, new ClientConfiguration().withRetryPolicy(PredefinedRetryPolicies.getDefaultRetryPolicyWithCustomMaxRetries(0))).withEndpoint("http://localhost:${UNUSABLE_PORT}") } def "naughty request handler doesn't break the trace"() { @@ -325,6 +356,7 @@ class AWSClientTest extends AgentTestRunner { "aws.endpoint" "$server.address" "aws.operation" "GetObjectRequest" "aws.agent" "java-aws-sdk" + "aws.bucket.name" "someBucket" try { errorTags AmazonClientException, ~/Unable to execute HTTP request/ } catch (AssertionError e) { diff --git a/dd-java-agent/instrumentation/aws-java-sdk-1.11.0/src/test_before_1_11_106/groovy/AWSClientTest.groovy b/dd-java-agent/instrumentation/aws-java-sdk-1.11.0/src/test_before_1_11_106/groovy/AWSClientTest.groovy index e466674178..c8278c321b 100644 --- a/dd-java-agent/instrumentation/aws-java-sdk-1.11.0/src/test_before_1_11_106/groovy/AWSClientTest.groovy +++ b/dd-java-agent/instrumentation/aws-java-sdk-1.11.0/src/test_before_1_11_106/groovy/AWSClientTest.groovy @@ -113,12 +113,15 @@ class AWSClientTest extends AgentTestRunner { "aws.endpoint" "$server.address" "aws.operation" "${operation}Request" "aws.agent" "java-aws-sdk" + for (def addedTag : additionalTags) { + "$addedTag.key" "$addedTag.value" + } defaultTags() } } span(1) { operationName "http.request" - resourceName "$method /$url" + resourceName "$method $path" spanType DDSpanTypes.HTTP_CLIENT errored false childOf(span(0)) @@ -127,7 +130,7 @@ class AWSClientTest extends AgentTestRunner { "$Tags.SPAN_KIND" Tags.SPAN_KIND_CLIENT "$Tags.PEER_HOSTNAME" "localhost" "$Tags.PEER_PORT" server.address.port - "$Tags.HTTP_URL" "$server.address/$url" + "$Tags.HTTP_URL" "${server.address}${path}" "$Tags.HTTP_METHOD" "$method" "$Tags.HTTP_STATUS" 200 defaultTags() @@ -139,23 +142,23 @@ class AWSClientTest extends AgentTestRunner { server.lastRequest.headers.get("x-datadog-parent-id") == null where: - service | operation | method | url | handlerCount | call | body | client - "S3" | "CreateBucket" | "PUT" | "testbucket/" | 1 | { client -> client.setS3ClientOptions(S3ClientOptions.builder().setPathStyleAccess(true).build()); client.createBucket("testbucket") } | "" | new AmazonS3Client().withEndpoint("http://localhost:$server.address.port") - "S3" | "GetObject" | "GET" | "someBucket/someKey" | 1 | { client -> client.getObject("someBucket", "someKey") } | "" | new AmazonS3Client().withEndpoint("http://localhost:$server.address.port") - "EC2" | "AllocateAddress" | "POST" | "" | 4 | { client -> client.allocateAddress() } | """ + service | operation | method | path | handlerCount | client | additionalTags | call | body + "S3" | "CreateBucket" | "PUT" | "/testbucket/" | 1 | new AmazonS3Client().withEndpoint("http://localhost:$server.address.port") | ["aws.bucket.name": "testbucket"] | { client -> client.setS3ClientOptions(S3ClientOptions.builder().setPathStyleAccess(true).build()); client.createBucket("testbucket") } | "" + "S3" | "GetObject" | "GET" | "/someBucket/someKey" | 1 | new AmazonS3Client().withEndpoint("http://localhost:$server.address.port") | ["aws.bucket.name": "someBucket"] | { client -> client.getObject("someBucket", "someKey") } | "" + "EC2" | "AllocateAddress" | "POST" | "/" | 4 | new AmazonEC2Client().withEndpoint("http://localhost:$server.address.port") | [:] | { client -> client.allocateAddress() } | """ 59dbff89-35bd-4eac-99ed-be587EXAMPLE 192.0.2.1 standard - """ | new AmazonEC2Client().withEndpoint("http://localhost:$server.address.port") - "RDS" | "DeleteOptionGroup" | "POST" | "" | 1 | { client -> client.deleteOptionGroup(new DeleteOptionGroupRequest()) } | """ + """ + "RDS" | "DeleteOptionGroup" | "POST" | "/" | 1 | new AmazonRDSClient().withEndpoint("http://localhost:$server.address.port") | [:] | { client -> client.deleteOptionGroup(new DeleteOptionGroupRequest()) } | """ 0ac9cda2-bbf4-11d3-f92b-31fa5e8dbc99 - """ | new AmazonRDSClient().withEndpoint("http://localhost:$server.address.port") + """ } def "send #operation request to closed port"() { @@ -186,6 +189,9 @@ class AWSClientTest extends AgentTestRunner { "aws.endpoint" "http://localhost:${UNUSABLE_PORT}" "aws.operation" "${operation}Request" "aws.agent" "java-aws-sdk" + for (def addedTag : additionalTags) { + "$addedTag.key" "$addedTag.value" + } errorTags AmazonClientException, ~/Unable to execute HTTP request/ defaultTags() } @@ -211,8 +217,8 @@ class AWSClientTest extends AgentTestRunner { } where: - service | operation | method | url | call | body | client - "S3" | "GetObject" | "GET" | "someBucket/someKey" | { client -> client.getObject("someBucket", "someKey") } | "" | new AmazonS3Client(CREDENTIALS_PROVIDER_CHAIN, new ClientConfiguration().withRetryPolicy(PredefinedRetryPolicies.getDefaultRetryPolicyWithCustomMaxRetries(0))).withEndpoint("http://localhost:${UNUSABLE_PORT}") + service | operation | method | url | call | additionalTags | body | client + "S3" | "GetObject" | "GET" | "someBucket/someKey" | { client -> client.getObject("someBucket", "someKey") } | ["aws.bucket.name": "someBucket"] | "" | new AmazonS3Client(CREDENTIALS_PROVIDER_CHAIN, new ClientConfiguration().withRetryPolicy(PredefinedRetryPolicies.getDefaultRetryPolicyWithCustomMaxRetries(0))).withEndpoint("http://localhost:${UNUSABLE_PORT}") } def "naughty request handler doesn't break the trace"() { @@ -249,6 +255,7 @@ class AWSClientTest extends AgentTestRunner { "aws.endpoint" "https://s3.amazonaws.com" "aws.operation" "GetObjectRequest" "aws.agent" "java-aws-sdk" + "aws.bucket.name" "someBucket" errorTags RuntimeException, "bad handler" defaultTags() } @@ -295,6 +302,7 @@ class AWSClientTest extends AgentTestRunner { "aws.endpoint" "http://localhost:$server.address.port" "aws.operation" "GetObjectRequest" "aws.agent" "java-aws-sdk" + "aws.bucket.name" "someBucket" errorTags AmazonClientException, ~/Unable to execute HTTP request/ defaultTags() } diff --git a/dd-java-agent/instrumentation/aws-java-sdk-2.2/src/main/java8/datadog/trace/instrumentation/aws/v2/AwsSdkClientDecorator.java b/dd-java-agent/instrumentation/aws-java-sdk-2.2/src/main/java8/datadog/trace/instrumentation/aws/v2/AwsSdkClientDecorator.java index 57cec8695c..42cee63615 100644 --- a/dd-java-agent/instrumentation/aws-java-sdk-2.2/src/main/java8/datadog/trace/instrumentation/aws/v2/AwsSdkClientDecorator.java +++ b/dd-java-agent/instrumentation/aws-java-sdk-2.2/src/main/java8/datadog/trace/instrumentation/aws/v2/AwsSdkClientDecorator.java @@ -22,21 +22,21 @@ public class AwsSdkClientDecorator extends HttpClientDecorator 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)); + request + .getValueForField("QueueName", String.class) + .ifPresent(name -> span.setTag("aws.queue.name", name)); // Kinesis request .getValueForField("StreamName", String.class) .ifPresent(name -> span.setTag("aws.stream.name", name)); + // DynamoDB + request + .getValueForField("TableName", String.class) + .ifPresent(name -> span.setTag("aws.table.name", name)); return span; }