Fix AWS version ranges
This commit is contained in:
parent
b7570c7152
commit
a3a1b08fa9
|
@ -0,0 +1,72 @@
|
|||
apply plugin: 'version-scan'
|
||||
|
||||
// Commented out because version scan doesn't catch the combination of tests.
|
||||
// HttpClientFactory is only present starting in 1.11.0
|
||||
// HandlerContextAware is added in 1.11.106
|
||||
// The combination of the two allow us to filter the ranges.
|
||||
//
|
||||
|
||||
//versionScan {
|
||||
// group = "com.amazonaws"
|
||||
// module = "aws-java-sdk-core"
|
||||
// versions = "[1.11.0,1.11.106)"
|
||||
// verifyPresent = [
|
||||
// "com.amazonaws.http.client.HttpClientFactory": null,
|
||||
// ]
|
||||
// verifyMissing = [
|
||||
// "com.amazonaws.HandlerContextAware",
|
||||
// ]
|
||||
//}
|
||||
|
||||
//versionScan {
|
||||
// group = "com.amazonaws"
|
||||
// module = "aws-java-sdk-core"
|
||||
// versions = "[1.11.0,)"
|
||||
// verifyPresent = [
|
||||
// "com.amazonaws.http.client.HttpClientFactory": null,
|
||||
// ]
|
||||
//}
|
||||
|
||||
versionScan {
|
||||
group = "com.amazonaws"
|
||||
module = "aws-java-sdk-core"
|
||||
versions = "[,1.11.106)"
|
||||
verifyMissing = [
|
||||
"com.amazonaws.HandlerContextAware",
|
||||
]
|
||||
}
|
||||
|
||||
apply from: "${rootDir}/gradle/java.gradle"
|
||||
|
||||
apply plugin: 'org.unbroken-dome.test-sets'
|
||||
|
||||
testSets {
|
||||
latestDepTest {
|
||||
dirName = 'test'
|
||||
}
|
||||
}
|
||||
|
||||
// These classes use Ratpack which requires Java 8. (Currently also incompatible with Java 9.)
|
||||
testJava8Only += '**/AWSClientTest.class'
|
||||
|
||||
dependencies {
|
||||
compileOnly group: 'com.amazonaws', name: 'aws-java-sdk-core', version: '1.11.0'
|
||||
|
||||
compile project(':dd-java-agent:agent-tooling')
|
||||
|
||||
compile deps.bytebuddy
|
||||
compile deps.opentracing
|
||||
annotationProcessor deps.autoservice
|
||||
implementation deps.autoservice
|
||||
|
||||
testCompile project(':dd-java-agent:testing')
|
||||
// Include httpclient instrumentation for testing because it is a dependency for aws-sdk.
|
||||
testCompile project(':dd-java-agent:instrumentation:apache-httpclient-4.3')
|
||||
testCompile group: 'com.amazonaws', name: 'aws-java-sdk', version: '1.11.0'
|
||||
}
|
||||
|
||||
configurations.latestDepTestCompile {
|
||||
resolutionStrategy {
|
||||
force group: 'com.amazonaws', name: 'aws-java-sdk', version: '1.11.105'
|
||||
}
|
||||
}
|
|
@ -0,0 +1,71 @@
|
|||
package datadog.trace.instrumentation.aws.v0;
|
||||
|
||||
import static datadog.trace.agent.tooling.ClassLoaderMatcher.classLoaderHasClasses;
|
||||
import static net.bytebuddy.matcher.ElementMatchers.declaresField;
|
||||
import static net.bytebuddy.matcher.ElementMatchers.isAbstract;
|
||||
import static net.bytebuddy.matcher.ElementMatchers.isConstructor;
|
||||
import static net.bytebuddy.matcher.ElementMatchers.named;
|
||||
import static net.bytebuddy.matcher.ElementMatchers.not;
|
||||
|
||||
import com.amazonaws.handlers.RequestHandler2;
|
||||
import com.google.auto.service.AutoService;
|
||||
import datadog.trace.agent.tooling.DDAdvice;
|
||||
import datadog.trace.agent.tooling.DDTransformers;
|
||||
import datadog.trace.agent.tooling.HelperInjector;
|
||||
import datadog.trace.agent.tooling.Instrumenter;
|
||||
import io.opentracing.util.GlobalTracer;
|
||||
import java.util.List;
|
||||
import net.bytebuddy.agent.builder.AgentBuilder;
|
||||
import net.bytebuddy.asm.Advice;
|
||||
|
||||
/**
|
||||
* This instrumentation might work with versions before 1.11.0, but this was the first version that
|
||||
* is tested. It could possibly be extended earlier.
|
||||
*/
|
||||
@AutoService(Instrumenter.class)
|
||||
public final class AWSClientInstrumentation extends Instrumenter.Configurable {
|
||||
|
||||
public AWSClientInstrumentation() {
|
||||
super("aws-sdk");
|
||||
}
|
||||
|
||||
@Override
|
||||
public AgentBuilder apply(final AgentBuilder agentBuilder) {
|
||||
return agentBuilder
|
||||
.type(
|
||||
isAbstract()
|
||||
.and(
|
||||
named("com.amazonaws.AmazonWebServiceClient")
|
||||
.and(declaresField(named("requestHandler2s")))),
|
||||
classLoaderHasClasses("com.amazonaws.http.client.HttpClientFactory")
|
||||
.and(
|
||||
not(
|
||||
classLoaderHasClasses(
|
||||
"com.amazonaws.client.builder.AwsClientBuilder$EndpointConfiguration"))))
|
||||
.transform(
|
||||
new HelperInjector(
|
||||
"datadog.trace.instrumentation.aws.v0.TracingRequestHandler",
|
||||
"datadog.trace.instrumentation.aws.v0.SpanDecorator"))
|
||||
.transform(DDTransformers.defaultTransformers())
|
||||
.transform(DDAdvice.create().advice(isConstructor(), AWSClientAdvice.class.getName()))
|
||||
.asDecorator();
|
||||
}
|
||||
|
||||
public static class AWSClientAdvice {
|
||||
// Since we're instrumenting the constructor, we can't add onThrowable.
|
||||
@Advice.OnMethodExit(suppress = Throwable.class)
|
||||
public static void addHandler(
|
||||
@Advice.FieldValue("requestHandler2s") final List<RequestHandler2> handlers) {
|
||||
boolean hasDDHandler = false;
|
||||
for (final RequestHandler2 handler : handlers) {
|
||||
if (handler instanceof TracingRequestHandler) {
|
||||
hasDDHandler = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!hasDDHandler) {
|
||||
handlers.add(new TracingRequestHandler(GlobalTracer.get()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -11,7 +11,7 @@
|
|||
* or implied. See the License for the specific language governing permissions and limitations under
|
||||
* the License.
|
||||
*/
|
||||
package datadog.trace.instrumentation.aws;
|
||||
package datadog.trace.instrumentation.aws.v0;
|
||||
|
||||
import com.amazonaws.AmazonWebServiceResponse;
|
||||
import com.amazonaws.Request;
|
|
@ -11,7 +11,7 @@
|
|||
* or implied. See the License for the specific language governing permissions and limitations under
|
||||
* the License.
|
||||
*/
|
||||
package datadog.trace.instrumentation.aws;
|
||||
package datadog.trace.instrumentation.aws.v0;
|
||||
|
||||
import com.amazonaws.AmazonWebServiceRequest;
|
||||
import com.amazonaws.Request;
|
||||
|
@ -48,11 +48,6 @@ public class TracingRequestHandler extends RequestHandler2 {
|
|||
this.tracer = tracer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AmazonWebServiceRequest beforeExecution(final AmazonWebServiceRequest request) {
|
||||
return request;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AmazonWebServiceRequest beforeMarshalling(final AmazonWebServiceRequest request) {
|
||||
return request;
|
|
@ -0,0 +1,173 @@
|
|||
import com.amazonaws.SDKGlobalConfiguration
|
||||
import com.amazonaws.auth.BasicAWSCredentials
|
||||
import com.amazonaws.handlers.RequestHandler2
|
||||
import com.amazonaws.services.ec2.AmazonEC2Client
|
||||
import com.amazonaws.services.rds.AmazonRDSClient
|
||||
import com.amazonaws.services.rds.model.DeleteOptionGroupRequest
|
||||
import com.amazonaws.services.s3.AmazonS3Client
|
||||
import com.amazonaws.services.s3.S3ClientOptions
|
||||
import datadog.trace.agent.test.AgentTestRunner
|
||||
import datadog.trace.api.DDTags
|
||||
import io.opentracing.tag.Tags
|
||||
import ratpack.http.Headers
|
||||
import spock.lang.Shared
|
||||
|
||||
import java.util.concurrent.atomic.AtomicReference
|
||||
|
||||
import static ratpack.groovy.test.embed.GroovyEmbeddedApp.ratpack
|
||||
|
||||
class AWSClientTest extends AgentTestRunner {
|
||||
def setupSpec() {
|
||||
System.setProperty(SDKGlobalConfiguration.ACCESS_KEY_SYSTEM_PROPERTY, "my-access-key")
|
||||
System.setProperty(SDKGlobalConfiguration.SECRET_KEY_SYSTEM_PROPERTY, "my-secret-key")
|
||||
}
|
||||
|
||||
def cleanupSpec() {
|
||||
System.clearProperty(SDKGlobalConfiguration.ACCESS_KEY_SYSTEM_PROPERTY)
|
||||
System.clearProperty(SDKGlobalConfiguration.SECRET_KEY_SYSTEM_PROPERTY)
|
||||
}
|
||||
|
||||
@Shared
|
||||
def receivedHeaders = new AtomicReference<Headers>()
|
||||
@Shared
|
||||
def responseBody = new AtomicReference<String>()
|
||||
@Shared
|
||||
def server = ratpack {
|
||||
handlers {
|
||||
all {
|
||||
receivedHeaders.set(request.headers)
|
||||
response.status(200).send(responseBody.get())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def "request handler is hooked up with constructor"() {
|
||||
setup:
|
||||
String accessKey = "asdf"
|
||||
String secretKey = "qwerty"
|
||||
def credentials = new BasicAWSCredentials(accessKey, secretKey)
|
||||
def client = new AmazonS3Client(credentials)
|
||||
if (addHandler) {
|
||||
client.addRequestHandler(new RequestHandler2() {})
|
||||
}
|
||||
|
||||
expect:
|
||||
client.requestHandler2s != null
|
||||
client.requestHandler2s.size() == size
|
||||
client.requestHandler2s.get(0).getClass().getSimpleName() == "TracingRequestHandler"
|
||||
|
||||
where:
|
||||
addHandler | size
|
||||
true | 2
|
||||
false | 1
|
||||
}
|
||||
|
||||
def "send #operation request with mocked response"() {
|
||||
setup:
|
||||
responseBody.set(body)
|
||||
def response = call.call(client)
|
||||
|
||||
expect:
|
||||
response != null
|
||||
|
||||
client.requestHandler2s != null
|
||||
client.requestHandler2s.size() == handlerCount
|
||||
client.requestHandler2s.get(0).getClass().getSimpleName() == "TracingRequestHandler"
|
||||
|
||||
TEST_WRITER.size() == 2
|
||||
|
||||
def trace = TEST_WRITER.get(0)
|
||||
trace.size() == 2
|
||||
|
||||
and: // span 0 - from apache-httpclient instrumentation
|
||||
def span1 = trace[0]
|
||||
|
||||
span1.context().operationName == "apache.http"
|
||||
span1.serviceName == "unnamed-java-app"
|
||||
span1.resourceName == "apache.http"
|
||||
span1.type == null
|
||||
!span1.context().getErrorFlag()
|
||||
span1.context().parentId == 0
|
||||
|
||||
|
||||
def tags1 = span1.context().tags
|
||||
tags1["component"] == "apache-httpclient"
|
||||
tags1["thread.name"] != null
|
||||
tags1["thread.id"] != null
|
||||
tags1.size() == 3
|
||||
|
||||
and: // span 1 - from apache-httpclient instrumentation
|
||||
def span2 = trace[1]
|
||||
|
||||
span2.context().operationName == "http.request"
|
||||
span2.serviceName == "unnamed-java-app"
|
||||
span2.resourceName == "$method /$url"
|
||||
span2.type == "http"
|
||||
!span2.context().getErrorFlag()
|
||||
span2.context().parentId == span1.spanId
|
||||
|
||||
|
||||
def tags2 = span2.context().tags
|
||||
tags2[Tags.SPAN_KIND.key] == Tags.SPAN_KIND_CLIENT
|
||||
tags2[Tags.HTTP_METHOD.key] == "$method"
|
||||
tags2[Tags.HTTP_URL.key] == "http://localhost:$server.address.port/$url"
|
||||
tags2[Tags.PEER_HOSTNAME.key] == "localhost"
|
||||
tags2[Tags.PEER_PORT.key] == server.address.port
|
||||
tags2[DDTags.THREAD_NAME] != null
|
||||
tags2[DDTags.THREAD_ID] != null
|
||||
tags2.size() == 9
|
||||
|
||||
and:
|
||||
|
||||
def trace2 = TEST_WRITER.get(1)
|
||||
trace2.size() == 1
|
||||
|
||||
and: // span 0 - from aws instrumentation
|
||||
def span = trace2[0]
|
||||
|
||||
span.context().operationName == "aws.http"
|
||||
span.serviceName == "java-aws-sdk"
|
||||
span.resourceName == "$service.$operation"
|
||||
span.type == "web"
|
||||
!span.context().getErrorFlag()
|
||||
span.context().parentId == 0
|
||||
|
||||
def tags = span.context().tags
|
||||
tags[Tags.COMPONENT.key] == "java-aws-sdk"
|
||||
tags[Tags.SPAN_KIND.key] == Tags.SPAN_KIND_CLIENT
|
||||
tags[Tags.HTTP_METHOD.key] == "$method"
|
||||
tags[Tags.HTTP_URL.key] == "http://localhost:$server.address.port"
|
||||
tags[Tags.HTTP_STATUS.key] == 200
|
||||
tags["aws.service"] == "Amazon $service" || tags["aws.service"] == "Amazon$service"
|
||||
tags["aws.endpoint"] == "http://localhost:$server.address.port"
|
||||
tags["aws.operation"] == "${operation}Request"
|
||||
tags["aws.agent"] == "java-aws-sdk"
|
||||
tags["params"] == params
|
||||
tags["span.type"] == "web"
|
||||
tags["thread.name"] != null
|
||||
tags["thread.id"] != null
|
||||
tags.size() == 13
|
||||
|
||||
receivedHeaders.get().get("x-datadog-trace-id") == "$span.traceId"
|
||||
receivedHeaders.get().get("x-datadog-parent-id") == "$span.spanId"
|
||||
|
||||
where:
|
||||
service | operation | method | url | handlerCount | call | body | params | 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() } | """
|
||||
<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>
|
||||
""" | "{Action=[AllocateAddress],Version=[2015-10-01]}" | new AmazonEC2Client().withEndpoint("http://localhost:$server.address.port")
|
||||
"RDS" | "DeleteOptionGroup" | "POST" | "" | 1 | { 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>
|
||||
""" | "{Action=[DeleteOptionGroup],Version=[2014-10-31]}" | new AmazonRDSClient().withEndpoint("http://localhost:$server.address.port")
|
||||
}
|
||||
}
|
|
@ -1,15 +1,11 @@
|
|||
// This results in download a LOT of modules. commenting out for now...
|
||||
|
||||
apply plugin: 'version-scan'
|
||||
|
||||
versionScan {
|
||||
group = "com.amazonaws"
|
||||
module = "aws-java-sdk-core"
|
||||
versions = "[1.11.0,)"
|
||||
versions = "[1.11.106,)"
|
||||
verifyPresent = [
|
||||
"com.amazonaws.http.client.HttpClientFactory" : null,
|
||||
"com.amazonaws.http.apache.utils.ApacheUtils" : null,
|
||||
"com.amazonaws.http.request.HttpRequestFactory": null,
|
||||
"com.amazonaws.HandlerContextAware": null,
|
||||
]
|
||||
}
|
||||
|
||||
|
@ -27,7 +23,7 @@ testSets {
|
|||
testJava8Only += '**/AWSClientTest.class'
|
||||
|
||||
dependencies {
|
||||
compileOnly group: 'com.amazonaws', name: 'aws-java-sdk-core', version: '1.11.119'
|
||||
compileOnly group: 'com.amazonaws', name: 'aws-java-sdk-core', version: '1.11.106'
|
||||
|
||||
compile project(':dd-java-agent:agent-tooling')
|
||||
|
||||
|
@ -39,7 +35,11 @@ dependencies {
|
|||
testCompile project(':dd-java-agent:testing')
|
||||
// Include httpclient instrumentation for testing because it is a dependency for aws-sdk.
|
||||
testCompile project(':dd-java-agent:instrumentation:apache-httpclient-4.3')
|
||||
testCompile group: 'com.amazonaws', name: 'aws-java-sdk', version: '1.11.119'
|
||||
|
||||
latestDepTestCompile group: 'com.amazonaws', name: 'aws-java-sdk', version: '+'
|
||||
testCompile group: 'com.amazonaws', name: 'aws-java-sdk', version: '1.11.106'
|
||||
}
|
||||
|
||||
configurations.latestDepTestCompile {
|
||||
resolutionStrategy {
|
||||
force group: 'com.amazonaws', name: 'aws-java-sdk', version: '+'
|
||||
}
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
package datadog.trace.instrumentation.aws;
|
||||
package datadog.trace.instrumentation.aws.v106;
|
||||
|
||||
import static datadog.trace.agent.tooling.ClassLoaderMatcher.classLoaderHasClasses;
|
||||
import static net.bytebuddy.matcher.ElementMatchers.declaresField;
|
||||
|
@ -17,6 +17,11 @@ import java.util.List;
|
|||
import net.bytebuddy.agent.builder.AgentBuilder;
|
||||
import net.bytebuddy.asm.Advice;
|
||||
|
||||
/**
|
||||
* The interface for com.amazonaws.Request changed in 106. The method addHandlerContext which is
|
||||
* used in TracingRequestHandler moved to a parent interface, which makes it source, but not
|
||||
* bytecode compatible. The instrumentation is the same, but the compiled output is different.
|
||||
*/
|
||||
@AutoService(Instrumenter.class)
|
||||
public final class AWSClientInstrumentation extends Instrumenter.Configurable {
|
||||
|
||||
|
@ -32,16 +37,11 @@ public final class AWSClientInstrumentation extends Instrumenter.Configurable {
|
|||
.and(
|
||||
named("com.amazonaws.AmazonWebServiceClient")
|
||||
.and(declaresField(named("requestHandler2s")))),
|
||||
classLoaderHasClasses(
|
||||
// aws classes used by opentracing contrib helpers
|
||||
"com.amazonaws.handlers.RequestHandler2",
|
||||
"com.amazonaws.Request",
|
||||
"com.amazonaws.Response",
|
||||
"com.amazonaws.handlers.HandlerContextKey"))
|
||||
classLoaderHasClasses("com.amazonaws.HandlerContextAware"))
|
||||
.transform(
|
||||
new HelperInjector(
|
||||
"datadog.trace.instrumentation.aws.TracingRequestHandler",
|
||||
"datadog.trace.instrumentation.aws.SpanDecorator"))
|
||||
"datadog.trace.instrumentation.aws.v106.TracingRequestHandler",
|
||||
"datadog.trace.instrumentation.aws.v106.SpanDecorator"))
|
||||
.transform(DDTransformers.defaultTransformers())
|
||||
.transform(DDAdvice.create().advice(isConstructor(), AWSClientAdvice.class.getName()))
|
||||
.asDecorator();
|
|
@ -0,0 +1,124 @@
|
|||
/*
|
||||
* Copyright 2017-2018 The OpenTracing Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
|
||||
* in compliance with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed under the License
|
||||
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
|
||||
* or implied. See the License for the specific language governing permissions and limitations under
|
||||
* the License.
|
||||
*/
|
||||
package datadog.trace.instrumentation.aws.v106;
|
||||
|
||||
import com.amazonaws.AmazonWebServiceResponse;
|
||||
import com.amazonaws.Request;
|
||||
import com.amazonaws.Response;
|
||||
import datadog.trace.api.DDTags;
|
||||
import io.opentracing.Span;
|
||||
import io.opentracing.tag.Tags;
|
||||
import java.io.PrintWriter;
|
||||
import java.io.StringWriter;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
class SpanDecorator {
|
||||
static final String COMPONENT_NAME = "java-aws-sdk";
|
||||
|
||||
private static final Map<String, String> SERVICE_NAMES = new ConcurrentHashMap<>();
|
||||
private static final Map<Class, String> OPERATION_NAMES = new ConcurrentHashMap<>();
|
||||
|
||||
static void onRequest(final Request<?> request, final Span span) {
|
||||
Tags.COMPONENT.set(span, COMPONENT_NAME);
|
||||
Tags.HTTP_METHOD.set(span, request.getHttpMethod().name());
|
||||
Tags.HTTP_URL.set(span, request.getEndpoint().toString());
|
||||
|
||||
final String awsServiceName = request.getServiceName();
|
||||
final Class<?> awsOperation = request.getOriginalRequest().getClass();
|
||||
|
||||
span.setTag("aws.agent", COMPONENT_NAME);
|
||||
span.setTag("aws.service", awsServiceName);
|
||||
span.setTag("aws.operation", awsOperation.getSimpleName());
|
||||
span.setTag("aws.endpoint", request.getEndpoint().toString());
|
||||
|
||||
span.setTag(
|
||||
DDTags.RESOURCE_NAME,
|
||||
remapServiceName(awsServiceName) + "." + remapOperationName(awsOperation));
|
||||
|
||||
try {
|
||||
final StringBuilder params = new StringBuilder("{");
|
||||
final Map<String, List<String>> requestParams = request.getParameters();
|
||||
boolean firstKey = true;
|
||||
for (final Entry<String, List<String>> entry : requestParams.entrySet()) {
|
||||
if (!firstKey) {
|
||||
params.append(",");
|
||||
}
|
||||
params.append(entry.getKey()).append("=[");
|
||||
for (int i = 0; i < entry.getValue().size(); ++i) {
|
||||
if (i > 0) {
|
||||
params.append(",");
|
||||
}
|
||||
params.append(entry.getValue().get(i));
|
||||
}
|
||||
params.append("]");
|
||||
firstKey = false;
|
||||
}
|
||||
params.append("}");
|
||||
span.setTag("params", params.toString());
|
||||
} catch (final Exception e) {
|
||||
try {
|
||||
org.slf4j.LoggerFactory.getLogger(SpanDecorator.class)
|
||||
.debug("Failed to decorate aws span", e);
|
||||
} catch (final Exception e2) {
|
||||
// can't reach logger. Silently eat excetpion.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void onResponse(final Response response, final Span span) {
|
||||
Tags.HTTP_STATUS.set(span, response.getHttpResponse().getStatusCode());
|
||||
if (response.getAwsResponse() instanceof AmazonWebServiceResponse) {
|
||||
final AmazonWebServiceResponse awsResp = (AmazonWebServiceResponse) response.getAwsResponse();
|
||||
span.setTag("aws.requestId", awsResp.getRequestId());
|
||||
}
|
||||
}
|
||||
|
||||
static void onError(final Throwable throwable, final Span span) {
|
||||
Tags.ERROR.set(span, Boolean.TRUE);
|
||||
span.log(errorLogs(throwable));
|
||||
}
|
||||
|
||||
private static Map<String, Object> errorLogs(final Throwable throwable) {
|
||||
final Map<String, Object> errorLogs = new HashMap<>(4);
|
||||
errorLogs.put("event", Tags.ERROR.getKey());
|
||||
errorLogs.put("error.kind", throwable.getClass().getName());
|
||||
errorLogs.put("error.object", throwable);
|
||||
|
||||
errorLogs.put("message", throwable.getMessage());
|
||||
|
||||
final StringWriter sw = new StringWriter();
|
||||
throwable.printStackTrace(new PrintWriter(sw));
|
||||
errorLogs.put("stack", sw.toString());
|
||||
|
||||
return errorLogs;
|
||||
}
|
||||
|
||||
private static String remapServiceName(final String serviceName) {
|
||||
if (!SERVICE_NAMES.containsKey(serviceName)) {
|
||||
SERVICE_NAMES.put(serviceName, serviceName.replace("Amazon", "").trim());
|
||||
}
|
||||
return SERVICE_NAMES.get(serviceName);
|
||||
}
|
||||
|
||||
private static String remapOperationName(final Class<?> awsOperation) {
|
||||
if (!OPERATION_NAMES.containsKey(awsOperation)) {
|
||||
OPERATION_NAMES.put(awsOperation, awsOperation.getSimpleName().replace("Request", ""));
|
||||
}
|
||||
return OPERATION_NAMES.get(awsOperation);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,92 @@
|
|||
/*
|
||||
* Copyright 2017-2018 The OpenTracing Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
|
||||
* in compliance with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed under the License
|
||||
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
|
||||
* or implied. See the License for the specific language governing permissions and limitations under
|
||||
* the License.
|
||||
*/
|
||||
package datadog.trace.instrumentation.aws.v106;
|
||||
|
||||
import com.amazonaws.AmazonWebServiceRequest;
|
||||
import com.amazonaws.Request;
|
||||
import com.amazonaws.Response;
|
||||
import com.amazonaws.handlers.HandlerContextKey;
|
||||
import com.amazonaws.handlers.RequestHandler2;
|
||||
import io.opentracing.Span;
|
||||
import io.opentracing.SpanContext;
|
||||
import io.opentracing.Tracer;
|
||||
import io.opentracing.propagation.Format;
|
||||
import io.opentracing.propagation.TextMapInjectAdapter;
|
||||
import io.opentracing.tag.Tags;
|
||||
|
||||
/** Tracing Request Handler */
|
||||
public class TracingRequestHandler extends RequestHandler2 {
|
||||
|
||||
private final HandlerContextKey<Span> contextKey = new HandlerContextKey<>("span");
|
||||
private final SpanContext parentContext; // for Async Client
|
||||
private final Tracer tracer;
|
||||
|
||||
public TracingRequestHandler(final Tracer tracer) {
|
||||
this.parentContext = null;
|
||||
this.tracer = tracer;
|
||||
}
|
||||
|
||||
/**
|
||||
* In case of Async Client: beforeRequest runs in separate thread therefore we need to inject
|
||||
* parent context to build chain
|
||||
*
|
||||
* @param parentContext parent context
|
||||
*/
|
||||
public TracingRequestHandler(final SpanContext parentContext, final Tracer tracer) {
|
||||
this.parentContext = parentContext;
|
||||
this.tracer = tracer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AmazonWebServiceRequest beforeMarshalling(final AmazonWebServiceRequest request) {
|
||||
return request;
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
@Override
|
||||
public void beforeRequest(final Request<?> request) {
|
||||
final Tracer.SpanBuilder spanBuilder =
|
||||
tracer.buildSpan("aws.command").withTag(Tags.SPAN_KIND.getKey(), Tags.SPAN_KIND_CLIENT);
|
||||
|
||||
if (parentContext != null) {
|
||||
spanBuilder.asChildOf(parentContext);
|
||||
}
|
||||
|
||||
final Span span = spanBuilder.start();
|
||||
SpanDecorator.onRequest(request, span);
|
||||
|
||||
tracer.inject(
|
||||
span.context(),
|
||||
Format.Builtin.HTTP_HEADERS,
|
||||
new TextMapInjectAdapter(request.getHeaders()));
|
||||
|
||||
request.addHandlerContext(contextKey, span);
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
@Override
|
||||
public void afterResponse(final Request<?> request, final Response<?> response) {
|
||||
final Span span = request.getHandlerContext(contextKey);
|
||||
SpanDecorator.onResponse(response, span);
|
||||
span.finish();
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
@Override
|
||||
public void afterError(final Request<?> request, final Response<?> response, final Exception e) {
|
||||
final Span span = request.getHandlerContext(contextKey);
|
||||
SpanDecorator.onError(e, span);
|
||||
span.finish();
|
||||
}
|
||||
}
|
|
@ -1,4 +1,5 @@
|
|||
import com.amazonaws.AmazonWebServiceClient
|
||||
import com.amazonaws.SDKGlobalConfiguration
|
||||
import com.amazonaws.auth.AWSStaticCredentialsProvider
|
||||
import com.amazonaws.auth.AnonymousAWSCredentials
|
||||
import com.amazonaws.auth.BasicAWSCredentials
|
||||
|
@ -21,6 +22,16 @@ import java.util.concurrent.atomic.AtomicReference
|
|||
import static ratpack.groovy.test.embed.GroovyEmbeddedApp.ratpack
|
||||
|
||||
class AWSClientTest extends AgentTestRunner {
|
||||
def setupSpec() {
|
||||
System.setProperty(SDKGlobalConfiguration.ACCESS_KEY_SYSTEM_PROPERTY, "my-access-key")
|
||||
System.setProperty(SDKGlobalConfiguration.SECRET_KEY_SYSTEM_PROPERTY, "my-secret-key")
|
||||
}
|
||||
|
||||
def cleanupSpec() {
|
||||
System.clearProperty(SDKGlobalConfiguration.ACCESS_KEY_SYSTEM_PROPERTY)
|
||||
System.clearProperty(SDKGlobalConfiguration.SECRET_KEY_SYSTEM_PROPERTY)
|
||||
}
|
||||
|
||||
@Shared
|
||||
def credentialsProvider = new AWSStaticCredentialsProvider(new AnonymousAWSCredentials())
|
||||
@Shared
|
|
@ -10,7 +10,8 @@ include ':dd-trace-api'
|
|||
|
||||
// instrumentation:
|
||||
include ':dd-java-agent:instrumentation:apache-httpclient-4.3'
|
||||
include ':dd-java-agent:instrumentation:aws-sdk'
|
||||
include ':dd-java-agent:instrumentation:aws-java-sdk-1.11.0'
|
||||
include ':dd-java-agent:instrumentation:aws-java-sdk-1.11.106'
|
||||
include ':dd-java-agent:instrumentation:classloaders'
|
||||
include ':dd-java-agent:instrumentation:datastax-cassandra-3.2'
|
||||
include ':dd-java-agent:instrumentation:hystrix-1.4'
|
||||
|
|
Loading…
Reference in New Issue