diff --git a/dd-java-agent/instrumentation/apache-httpclient-4.3/apache-httpclient-4.3.gradle b/dd-java-agent/instrumentation/apache-httpclient-4.3/apache-httpclient-4.3.gradle index b8deeab46c..d4ed32568a 100644 --- a/dd-java-agent/instrumentation/apache-httpclient-4.3/apache-httpclient-4.3.gradle +++ b/dd-java-agent/instrumentation/apache-httpclient-4.3/apache-httpclient-4.3.gradle @@ -13,17 +13,25 @@ versionScan { // "org.apache.http.HttpException" : null, // "org.apache.http.HttpRequest" : null, // "org.apache.http.client.RedirectStrategy" : null, - "org.apache.http.client.methods.CloseableHttpResponse" : null, - "org.apache.http.client.methods.HttpExecutionAware" : null, - "org.apache.http.client.methods.HttpRequestWrapper" : null, - "org.apache.http.client.protocol.HttpClientContext" : null, + "org.apache.http.client.methods.CloseableHttpResponse": null, + "org.apache.http.client.methods.HttpExecutionAware" : null, + "org.apache.http.client.methods.HttpRequestWrapper" : null, + "org.apache.http.client.protocol.HttpClientContext" : null, // "org.apache.http.conn.routing.HttpRoute" : null, - "org.apache.http.impl.execchain.ClientExecChain": null + "org.apache.http.impl.execchain.ClientExecChain" : null ] } apply from: "${rootDir}/gradle/java.gradle" +apply plugin: 'org.unbroken-dome.test-sets' + +testSets { + latestDepTest { + dirName = 'test' + } +} + dependencies { compileOnly group: 'org.apache.httpcomponents', name: 'httpclient', version: '4.3' @@ -33,4 +41,10 @@ dependencies { compile deps.opentracing annotationProcessor deps.autoservice implementation deps.autoservice + + testCompile project(':dd-java-agent:testing') + testCompile group: 'org.apache.httpcomponents', name: 'httpclient', version: '4.3' + + + latestDepTestCompile group: 'org.apache.httpcomponents', name: 'httpclient', version: '+' } diff --git a/dd-java-agent-ittests/src/test/groovy/datadog/trace/agent/integration/httpclient/ApacheHttpClientTest.groovy b/dd-java-agent/instrumentation/apache-httpclient-4.3/src/test/groovy/ApacheHttpClientTest.groovy similarity index 54% rename from dd-java-agent-ittests/src/test/groovy/datadog/trace/agent/integration/httpclient/ApacheHttpClientTest.groovy rename to dd-java-agent/instrumentation/apache-httpclient-4.3/src/test/groovy/ApacheHttpClientTest.groovy index d378079ad8..791cbc39fe 100644 --- a/dd-java-agent-ittests/src/test/groovy/datadog/trace/agent/integration/httpclient/ApacheHttpClientTest.groovy +++ b/dd-java-agent/instrumentation/apache-httpclient-4.3/src/test/groovy/ApacheHttpClientTest.groovy @@ -1,38 +1,49 @@ -package datadog.trace.agent.integration.httpclient - import datadog.opentracing.DDSpan -import datadog.opentracing.DDTracer -import datadog.trace.agent.integration.TestHttpServer -import datadog.trace.agent.test.IntegrationTestUtils +import datadog.trace.agent.test.AgentTestRunner import datadog.trace.api.DDSpanTypes -import datadog.trace.common.writer.ListWriter +import io.opentracing.Scope +import io.opentracing.SpanContext +import io.opentracing.propagation.Format +import io.opentracing.propagation.TextMap import io.opentracing.tag.Tags +import io.opentracing.util.GlobalTracer import org.apache.http.HttpResponse import org.apache.http.client.HttpClient import org.apache.http.client.methods.HttpGet import org.apache.http.impl.client.HttpClientBuilder import org.apache.http.message.BasicHeader +import ratpack.handling.Context import spock.lang.Shared -import spock.lang.Specification -class ApacheHttpClientTest extends Specification { +import static datadog.trace.agent.test.TestUtils.runUnderTrace +import static ratpack.groovy.test.embed.GroovyEmbeddedApp.ratpack + +class ApacheHttpClientTest extends AgentTestRunner { @Shared - def writer = new ListWriter() - @Shared - def tracer = new DDTracer(writer) + def server = ratpack { + handlers { + get { + String msg = "

Hello test.

\n" + boolean isDDServer = true + if (context.request.getHeaders().contains("is-dd-server")) { + isDDServer = Boolean.parseBoolean(context.request.getHeaders().get("is-dd-server")) + } + if (isDDServer) { + final SpanContext extractedContext = + GlobalTracer.get() + .extract(Format.Builtin.HTTP_HEADERS, new RatpackResponseAdapter(context)) + Scope scope = + GlobalTracer.get() + .buildSpan("test-http-server") + .asChildOf(extractedContext) + .startActive(true) + scope.close() + } - def setupSpec() { - IntegrationTestUtils.registerOrReplaceGlobalTracer(tracer) - TestHttpServer.startServer() - } - - def cleanupSpec() { - TestHttpServer.stopServer() - } - - def setup() { - writer.clear() + response.status(200).send(msg) + } + } } def "trace request with propagation"() { @@ -40,10 +51,9 @@ class ApacheHttpClientTest extends Specification { final HttpClientBuilder builder = HttpClientBuilder.create() final HttpClient client = builder.build() - IntegrationTestUtils.runUnderTrace("someTrace") { + runUnderTrace("someTrace") { try { - HttpResponse response = - client.execute(new HttpGet(new URI("http://localhost:" + TestHttpServer.getPort()))) + HttpResponse response = client.execute(new HttpGet(server.getAddress())) assert response.getStatusLine().getStatusCode() == 200 } catch (Exception e) { e.printStackTrace() @@ -53,11 +63,11 @@ class ApacheHttpClientTest extends Specification { expect: // one trace on the server, one trace on the client - writer.size() == 2 - final List serverTrace = writer.get(0) + TEST_WRITER.size() == 2 + final List serverTrace = TEST_WRITER.get(0) serverTrace.size() == 1 - final List clientTrace = writer.get(1) + final List clientTrace = TEST_WRITER.get(1) clientTrace.size() == 3 clientTrace.get(0).getOperationName() == "someTrace" // our instrumentation makes 2 spans for apache-httpclient @@ -71,9 +81,9 @@ class ApacheHttpClientTest extends Specification { clientSpan.getType() == DDSpanTypes.HTTP_CLIENT clientSpan.getTags()[Tags.HTTP_METHOD.getKey()] == "GET" clientSpan.getTags()[Tags.HTTP_STATUS.getKey()] == 200 - clientSpan.getTags()[Tags.HTTP_URL.getKey()] == "http://localhost:" + TestHttpServer.getPort() + clientSpan.getTags()[Tags.HTTP_URL.getKey()] == server.getAddress().toString() clientSpan.getTags()[Tags.PEER_HOSTNAME.getKey()] == "localhost" - clientSpan.getTags()[Tags.PEER_PORT.getKey()] == TestHttpServer.getPort() + clientSpan.getTags()[Tags.PEER_PORT.getKey()] == server.getAddress().port clientSpan.getTags()[Tags.SPAN_KIND.getKey()] == Tags.SPAN_KIND_CLIENT // client trace propagates to server @@ -82,17 +92,15 @@ class ApacheHttpClientTest extends Specification { clientSpan.getSpanId() == serverTrace.get(0).getParentId() } - def "trace request without propagation"() { setup: final HttpClientBuilder builder = HttpClientBuilder.create() final HttpClient client = builder.build() - IntegrationTestUtils.runUnderTrace("someTrace") { + runUnderTrace("someTrace") { try { - HttpGet request = new HttpGet(new URI("http://localhost:" - + TestHttpServer.getPort())) - request.addHeader(new BasicHeader(TestHttpServer.IS_DD_SERVER, "false")) + HttpGet request = new HttpGet(server.getAddress()) + request.addHeader(new BasicHeader("is-dd-server", "false")) HttpResponse response = client.execute(request) assert response.getStatusLine().getStatusCode() == 200 } catch (Exception e) { @@ -102,8 +110,8 @@ class ApacheHttpClientTest extends Specification { } expect: // only one trace (client). - writer.size() == 1 - final List clientTrace = writer.get(0) + TEST_WRITER.size() == 1 + final List clientTrace = TEST_WRITER.get(0) clientTrace.size() == 3 clientTrace.get(0).getOperationName() == "someTrace" // our instrumentation makes 2 spans for apache-httpclient @@ -115,10 +123,27 @@ class ApacheHttpClientTest extends Specification { clientSpan.getOperationName() == "http.request" clientSpan.getTags()[Tags.HTTP_METHOD.getKey()] == "GET" clientSpan.getTags()[Tags.HTTP_STATUS.getKey()] == 200 - clientSpan.getTags()[Tags.HTTP_URL.getKey()] == "http://localhost:" + TestHttpServer.getPort() + clientSpan.getTags()[Tags.HTTP_URL.getKey()] == server.getAddress().toString() clientSpan.getTags()[Tags.PEER_HOSTNAME.getKey()] == "localhost" - clientSpan.getTags()[Tags.PEER_PORT.getKey()] == TestHttpServer.getPort() + clientSpan.getTags()[Tags.PEER_PORT.getKey()] == server.getAddress().port clientSpan.getTags()[Tags.SPAN_KIND.getKey()] == Tags.SPAN_KIND_CLIENT } + private static class RatpackResponseAdapter implements TextMap { + final Context context + + RatpackResponseAdapter(Context context) { + this.context = context + } + + @Override + void put(String key, String value) { + context.response.set(key, value) + } + + @Override + Iterator> iterator() { + return context.request.getHeaders().asMultiValueMap().entrySet().iterator() + } + } } diff --git a/dd-trace-ot/src/main/java/datadog/opentracing/PendingTrace.java b/dd-trace-ot/src/main/java/datadog/opentracing/PendingTrace.java index 6f77f1980c..06f0f4b19d 100644 --- a/dd-trace-ot/src/main/java/datadog/opentracing/PendingTrace.java +++ b/dd-trace-ot/src/main/java/datadog/opentracing/PendingTrace.java @@ -196,14 +196,19 @@ public class PendingTrace extends ConcurrentLinkedDeque { void start() { executorService.scheduleAtFixedRate(new SpanCleaner(), 0, CLEAN_FREQUENCY, TimeUnit.SECONDS); - Runtime.getRuntime() - .addShutdownHook( - new Thread() { - @Override - public void run() { - PendingTrace.SpanCleaner.this.close(); - } - }); + try { + Runtime.getRuntime() + .addShutdownHook( + new Thread() { + @Override + public void run() { + PendingTrace.SpanCleaner.this.close(); + } + }); + } catch (final IllegalStateException ex) { + // The JVM might be shutting down. + log.debug("Error adding shutdown hook.", ex); + } } @Override