Add various tags for AWS SDK v1.x
This brings it inline with the v2 instrumentation.
MODIFY
dd-java-agent/instrumentation/aws-java-sdk-1.11.0/aws-java-sdk-1.11.0.gradle
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

MODIFY
dd-java-agent/instrumentation/aws-java-sdk-1.11.0/src/main/java/datadog/trace/instrumentation/aws/v0/AWSClientInstrumentation.java
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<String, String> 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)));
}
}
}

MODIFY
dd-java-agent/instrumentation/aws-java-sdk-1.11.0/src/main/java/datadog/trace/instrumentation/aws/v0/AWSHttpClientInstrumentation.java
dd-java-agent/instrumentation/aws-java-sdk-1.11.0/src/main/java/datadog/trace/instrumentation/aws/v0/AWSHttpClientInstrumentation.java
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();

MODIFY
dd-java-agent/instrumentation/aws-java-sdk-1.11.0/src/main/java/datadog/trace/instrumentation/aws/v0/AwsSdkClientDecorator.java
dd-java-agent/instrumentation/aws-java-sdk-1.11.0/src/main/java/datadog/trace/instrumentation/aws/v0/AwsSdkClientDecorator.java
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<Request, Response> {
- public static final AwsSdkClientDecorator DECORATE = new AwsSdkClientDecorator();
static final String COMPONENT_NAME = "java-aws-sdk";
private final Map<String, String> serviceNames = new ConcurrentHashMap<>();
private final Map<Class, String> operationNames = new ConcurrentHashMap<>();
+ private final ContextStore<AmazonWebServiceRequest, RequestMeta> contextStore;
+
+ public AwsSdkClientDecorator(
+ final ContextStore<AmazonWebServiceRequest, RequestMeta> contextStore) {
+ this.contextStore = contextStore;
+ }
@Override
public AgentSpan onRequest(final AgentSpan span, final Request request) {
@@ -25,7 +32,8 @@ public class AwsSdkClientDecorator extends HttpClientDecorator<Request, Response
super.onRequest(span, request);
final String awsServiceName = request.getServiceName();
- final Class<?> 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<Request, Response
DDTags.RESOURCE_NAME,
remapServiceName(awsServiceName) + "." + remapOperationName(awsOperation));
+ if (contextStore != null) {
+ final RequestMeta requestMeta = contextStore.get(originalRequest);
+ if (requestMeta != null) {
+ span.setTag("aws.bucket.name", requestMeta.getBucketName());
+ span.setTag("aws.queue.url", requestMeta.getQueueUrl());
+ span.setTag("aws.queue.name", requestMeta.getQueueName());
+ span.setTag("aws.stream.name", requestMeta.getStreamName());
+ span.setTag("aws.table.name", requestMeta.getTableName());
+ }
+ }
+
return span;
}

ADD
dd-java-agent/instrumentation/aws-java-sdk-1.11.0/src/main/java/datadog/trace/instrumentation/aws/v0/OnErrorDecorator.java
+package datadog.trace.instrumentation.aws.v0;
+
+import datadog.trace.agent.decorator.BaseDecorator;
+
+public class OnErrorDecorator extends BaseDecorator {
+ public static final OnErrorDecorator DECORATE = new OnErrorDecorator();
+
+ @Override
+ protected String[] instrumentationNames() {
+ return new String[] {"aws-sdk"};
+ }
+
+ @Override
+ protected String spanType() {
+ return null;
+ }
+
+ @Override
+ protected String component() {
+ return "java-aws-sdk";
+ }
+}

ADD
dd-java-agent/instrumentation/aws-java-sdk-1.11.0/src/main/java/datadog/trace/instrumentation/aws/v0/RequestInstrumentation.java
+package datadog.trace.instrumentation.aws.v0;
+
+import static datadog.trace.agent.tooling.ByteBuddyElementMatchers.safeHasSuperType;
+import static java.util.Collections.singletonMap;
+import static net.bytebuddy.matcher.ElementMatchers.named;
+import static net.bytebuddy.matcher.ElementMatchers.takesArgument;
+
+import com.amazonaws.AmazonWebServiceRequest;
+import com.google.auto.service.AutoService;
+import datadog.trace.agent.tooling.Instrumenter;
+import datadog.trace.bootstrap.ContextStore;
+import datadog.trace.bootstrap.InstrumentationContext;
+import java.util.HashMap;
+import java.util.Map;
+import net.bytebuddy.asm.Advice;
+import net.bytebuddy.description.method.MethodDescription;
+import net.bytebuddy.description.type.TypeDescription;
+import net.bytebuddy.matcher.ElementMatcher;
+
+@AutoService(Instrumenter.class)
+public final class RequestInstrumentation extends Instrumenter.Default {
+
+ public RequestInstrumentation() {
+ super("aws-sdk");
+ }
+
+ @Override
+ public ElementMatcher<TypeDescription> typeMatcher() {
+ return safeHasSuperType(named("com.amazonaws.AmazonWebServiceRequest"));
+ }
+
+ @Override
+ public String[] helperClassNames() {
+ return new String[] {
+ packageName + ".RequestMeta",
+ };
+ }
+
+ @Override
+ public Map<? extends ElementMatcher<? super MethodDescription>, String> transformers() {
+ final Map<ElementMatcher<? super MethodDescription>, 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<String, String> 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<AmazonWebServiceRequest, RequestMeta> 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<AmazonWebServiceRequest, RequestMeta> 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<AmazonWebServiceRequest, RequestMeta> 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<AmazonWebServiceRequest, RequestMeta> 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<AmazonWebServiceRequest, RequestMeta> 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);
+ }
+ }
+}

ADD
dd-java-agent/instrumentation/aws-java-sdk-1.11.0/src/main/java/datadog/trace/instrumentation/aws/v0/RequestMeta.java
+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<AgentScope> SCOPE_CONTEXT_KEY =
+ new HandlerContextKey<>("DatadogScope");
+
+ private String bucketName;
+ private String queueUrl;
+ private String queueName;
+ private String streamName;
+ private String tableName;
+}

MODIFY
dd-java-agent/instrumentation/aws-java-sdk-1.11.0/src/main/java/datadog/trace/instrumentation/aws/v0/TracingRequestHandler.java
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<AgentScope> SCOPE_CONTEXT_KEY =
- new HandlerContextKey<>("DatadogScope");
+ private final AwsSdkClientDecorator decorate;
+
+ public TracingRequestHandler(
+ final ContextStore<AmazonWebServiceRequest, RequestMeta> 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();
}
}

MODIFY
dd-java-agent/instrumentation/aws-java-sdk-1.11.0/src/test/groovy/AWSClientTest.groovy
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() } | """
+ 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"] | """
+ <CreateQueueResponse>
+ <CreateQueueResult><QueueUrl>https://queue.amazonaws.com/123456789012/MyQueue</QueueUrl></CreateQueueResult>
+ <ResponseMetadata><RequestId>7a62c49f-347e-4fc4-9331-6e8e7a96aa73</RequestId></ResponseMetadata>
+ </CreateQueueResponse>
+ """
+ "SQS" | "SendMessage" | "POST" | "/someurl" | 4 | AmazonSQSClientBuilder.standard().withEndpointConfiguration(endpoint).withCredentials(credentialsProvider).build() | { c -> c.sendMessage(new SendMessageRequest("someurl", "")) } | ["aws.queue.url": "someurl"] | """
+ <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" | "/" | 4 | AmazonEC2ClientBuilder.standard().withEndpointConfiguration(endpoint).withCredentials(credentialsProvider).build() | { client -> client.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>
- """ | AmazonEC2ClientBuilder.standard().withEndpointConfiguration(endpoint).withCredentials(credentialsProvider).build()
- "RDS" | "DeleteOptionGroup" | "POST" | "" | 5 | { client -> client.deleteOptionGroup(new DeleteOptionGroupRequest()) } | """
+ """
+ "RDS" | "DeleteOptionGroup" | "POST" | "/" | 5 | AmazonRDSClientBuilder.standard().withEndpointConfiguration(endpoint).withCredentials(credentialsProvider).build() | { client -> client.deleteOptionGroup(new DeleteOptionGroupRequest()) } | [:] | """
<DeleteOptionGroupResponse xmlns="http://rds.amazonaws.com/doc/2014-09-01/">
<ResponseMetadata>
<RequestId>0ac9cda2-bbf4-11d3-f92b-31fa5e8dbc99</RequestId>
</ResponseMetadata>
</DeleteOptionGroupResponse>
- """ | 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) {

MODIFY
dd-java-agent/instrumentation/aws-java-sdk-1.11.0/src/test_before_1_11_106/groovy/AWSClientTest.groovy
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() } | """
<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>
- """ | 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()) } | """
<DeleteOptionGroupResponse xmlns="http://rds.amazonaws.com/doc/2014-09-01/">
<ResponseMetadata>
<RequestId>0ac9cda2-bbf4-11d3-f92b-31fa5e8dbc99</RequestId>
</ResponseMetadata>
</DeleteOptionGroupResponse>
- """ | 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()
}

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
@@ -22,21 +22,21 @@ public class AwsSdkClientDecorator extends HttpClientDecorator<SdkHttpRequest, S
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));
+ 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;
}

Add various tags for AWS SDK v1.x

This brings it inline with the v2 instrumentation.