Merge pull request #1158 from DataDog/tyler/aws-1-tagging

Add various tags for AWS SDK v1.x
This commit is contained in:
Tyler Benson 2020-01-03 08:38:56 -08:00 committed by GitHub
commit 03dd908fdb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 332 additions and 60 deletions

View File

@ -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

View File

@ -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)));
}
}
}

View File

@ -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();

View File

@ -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<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;
}

View File

@ -0,0 +1,22 @@
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";
}
}

View File

@ -0,0 +1,144 @@
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);
}
}
}

View File

@ -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<AgentScope> SCOPE_CONTEXT_KEY =
new HandlerContextKey<>("DatadogScope");
private String bucketName;
private String queueUrl;
private String queueName;
private String streamName;
private String tableName;
}

View File

@ -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();
}
}

View File

@ -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() } | """
<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()) } | """
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>
"""
"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) {

View File

@ -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()
}

View File

@ -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;
}