From c9da16f3347992008b54c479b50a19693224886a Mon Sep 17 00:00:00 2001 From: Tyler Benson Date: Mon, 12 Feb 2018 14:00:43 +1000 Subject: [PATCH] Add resource naming instrumentation for jax-rs --- .../instrumentation/jax-rs/jax-rs.gradle | 26 +++++ .../jaxrs/JaxRsInstrumentation.java | 100 +++++++++++++++++ .../groovy/JaxRsInstrumentationTest.groovy | 105 ++++++++++++++++++ .../jax-rs/src/test/groovy/JerseyTest.groovy | 33 ++++++ .../jax-rs/src/test/java/TestResource.java | 13 +++ .../kafka-clients-0.11.gradle | 2 +- .../src/test/groovy/KafkaClientTest.groovy | 5 - .../kafka-streams-0.11.gradle | 2 +- .../src/test/groovy/KafkaStreamsTest.groovy | 5 +- dd-java-agent/src/test/resources/logback.xml | 2 +- .../trace/agent/test/AgentTestRunner.java | 70 +++++++++++- dd-java-agent/testing/testing.gradle | 1 + .../trace/agent/tooling/AgentInstaller.java | 6 +- .../trace/common/writer/ListWriter.java | 8 +- settings.gradle | 1 + 15 files changed, 363 insertions(+), 16 deletions(-) create mode 100644 dd-java-agent/instrumentation/jax-rs/jax-rs.gradle create mode 100644 dd-java-agent/instrumentation/jax-rs/src/main/java/datadog/trace/instrumentation/jaxrs/JaxRsInstrumentation.java create mode 100644 dd-java-agent/instrumentation/jax-rs/src/test/groovy/JaxRsInstrumentationTest.groovy create mode 100644 dd-java-agent/instrumentation/jax-rs/src/test/groovy/JerseyTest.groovy create mode 100644 dd-java-agent/instrumentation/jax-rs/src/test/java/TestResource.java diff --git a/dd-java-agent/instrumentation/jax-rs/jax-rs.gradle b/dd-java-agent/instrumentation/jax-rs/jax-rs.gradle new file mode 100644 index 0000000000..43d5255cae --- /dev/null +++ b/dd-java-agent/instrumentation/jax-rs/jax-rs.gradle @@ -0,0 +1,26 @@ +apply plugin: 'version-scan' + +versionScan { + group = "javax.ws.rs" + module = "jsr311-api" + versions = "(,)" +} + +apply from: "${rootDir}/gradle/java.gradle" + +dependencies { + compileOnly group: 'javax.ws.rs', name: 'jsr311-api', version: '1.1.1' + + compile deps.bytebuddy + compile deps.opentracing + compile deps.autoservice + + compile project(':dd-trace-ot') + compile project(':dd-java-agent:tooling') + + testCompile project(':dd-java-agent:testing') + testCompile group: 'com.sun.jersey', name: 'jersey-core', version: '1.19.4' + testCompile group: 'com.sun.jersey', name: 'jersey-servlet', version: '1.19.4' + testCompile group: 'io.dropwizard', name: 'dropwizard-testing', version: '0.7.1' + testCompile group: 'javax.xml.bind', name: 'jaxb-api', version: '2.2.3' +} diff --git a/dd-java-agent/instrumentation/jax-rs/src/main/java/datadog/trace/instrumentation/jaxrs/JaxRsInstrumentation.java b/dd-java-agent/instrumentation/jax-rs/src/main/java/datadog/trace/instrumentation/jaxrs/JaxRsInstrumentation.java new file mode 100644 index 0000000000..2a6905b72d --- /dev/null +++ b/dd-java-agent/instrumentation/jax-rs/src/main/java/datadog/trace/instrumentation/jaxrs/JaxRsInstrumentation.java @@ -0,0 +1,100 @@ +package datadog.trace.instrumentation.jaxrs; + +import static net.bytebuddy.matcher.ElementMatchers.declaresMethod; +import static net.bytebuddy.matcher.ElementMatchers.hasSuperType; +import static net.bytebuddy.matcher.ElementMatchers.isAnnotatedWith; +import static net.bytebuddy.matcher.ElementMatchers.named; + +import com.google.auto.service.AutoService; +import datadog.trace.agent.tooling.DDAdvice; +import datadog.trace.agent.tooling.Instrumenter; +import datadog.trace.api.DDTags; +import io.opentracing.Scope; +import io.opentracing.tag.Tags; +import io.opentracing.util.GlobalTracer; +import java.lang.annotation.Annotation; +import java.lang.reflect.Method; +import java.util.LinkedList; +import javax.ws.rs.HttpMethod; +import javax.ws.rs.Path; +import net.bytebuddy.agent.builder.AgentBuilder; +import net.bytebuddy.asm.Advice; + +@AutoService(Instrumenter.class) +public final class JaxRsInstrumentation extends Instrumenter.Configurable { + + public JaxRsInstrumentation() { + super("jax-rs", "jaxrs"); + } + + @Override + protected boolean defaultEnabled() { + return false; + } + + @Override + protected AgentBuilder apply(final AgentBuilder agentBuilder) { + return agentBuilder + .type( + hasSuperType( + isAnnotatedWith(named("javax.ws.rs.Path")) + .or(hasSuperType(declaresMethod(isAnnotatedWith(named("javax.ws.rs.Path"))))))) + .transform( + DDAdvice.create() + .advice( + isAnnotatedWith( + named("javax.ws.rs.Path") + .or(named("javax.ws.rs.DELETE")) + .or(named("javax.ws.rs.GET")) + .or(named("javax.ws.rs.HEAD")) + .or(named("javax.ws.rs.OPTIONS")) + .or(named("javax.ws.rs.POST")) + .or(named("javax.ws.rs.PUT"))), + JaxRsAdvice.class.getName())) + .asDecorator(); + } + + public static class JaxRsAdvice { + + @Advice.OnMethodEnter(suppress = Throwable.class) + public static void nameSpan(@Advice.This final Object obj, @Advice.Origin final Method method) { + // TODO: do we need caching for this? + + final LinkedList classPaths = new LinkedList<>(); + Class target = obj.getClass(); + while (target != Object.class) { + final Path annotation = target.getAnnotation(Path.class); + if (annotation != null) { + classPaths.push(annotation); + } + target = target.getSuperclass(); + } + final Path methodPath = method.getAnnotation(Path.class); + String httpMethod = null; + for (final Annotation ann : method.getDeclaredAnnotations()) { + if (ann.annotationType().getAnnotation(HttpMethod.class) != null) { + httpMethod = ann.annotationType().getSimpleName(); + } + } + + final StringBuilder resourceNameBuilder = new StringBuilder(); + if (httpMethod != null) { + resourceNameBuilder.append(httpMethod); + resourceNameBuilder.append(" "); + } + for (final Path classPath : classPaths) { + resourceNameBuilder.append(classPath.value()); + } + if (methodPath != null) { + resourceNameBuilder.append(methodPath.value()); + } + final String resourceName = resourceNameBuilder.toString().trim(); + + final Scope scope = GlobalTracer.get().scopeManager().active(); + if (scope != null && !resourceName.isEmpty()) { + scope.span().setTag(DDTags.RESOURCE_NAME, resourceName); + Tags.COMPONENT.set(scope.span(), "jax-rs"); + } + } + } +} diff --git a/dd-java-agent/instrumentation/jax-rs/src/test/groovy/JaxRsInstrumentationTest.groovy b/dd-java-agent/instrumentation/jax-rs/src/test/groovy/JaxRsInstrumentationTest.groovy new file mode 100644 index 0000000000..aac223e674 --- /dev/null +++ b/dd-java-agent/instrumentation/jax-rs/src/test/groovy/JaxRsInstrumentationTest.groovy @@ -0,0 +1,105 @@ +import datadog.opentracing.DDSpanContext +import datadog.trace.agent.test.AgentTestRunner +import io.opentracing.util.GlobalTracer +import spock.lang.Unroll + +import javax.ws.rs.* + +class JaxRsInstrumentationTest extends AgentTestRunner { + + static { + System.setProperty("dd.integration.jax-rs.enabled", "true") + } + + @Unroll + def "span named '#resourceName' from annotations on class"() { + setup: + def scope = GlobalTracer.get().buildSpan("test").startActive(false) + DDSpanContext spanContext = scope.span().context() + obj.call() + + expect: + spanContext.resourceName == resourceName + + cleanup: + scope.close() + + where: + resourceName | obj + "test" | new Jax() { + // invalid because no annotations + void call() {} + } + "/a" | new Jax() { + @Path("/a") + void call() {} + } + "GET /b" | new Jax() { + @GET + @Path("/b") + void call() {} + } + "test" | new InterfaceWithPath() { + // invalid because no annotations + void call() {} + } + "POST /c" | new InterfaceWithPath() { + @POST + @Path("/c") + void call() {} + } + "HEAD" | new InterfaceWithPath() { + @HEAD + void call() {} + } + "test" | new AbstractClassWithPath() { + // invalid because no annotations + void call() {} + } + "POST /abstract/d" | new AbstractClassWithPath() { + @POST + @Path("/d") + void call() {} + } + "PUT /abstract" | new AbstractClassWithPath() { + @PUT + void call() {} + } + "test" | new ChildClassWithPath() { + // invalid because no annotations + void call() {} + } + "OPTIONS /abstract/child/e" | new ChildClassWithPath() { + @OPTIONS + @Path("/e") + void call() {} + } + "DELETE /abstract/child" | new ChildClassWithPath() { + @DELETE + void call() {} + } + "POST /abstract/child" | new ChildClassWithPath() + } + + interface Jax { + void call() + } + + @Path("/interface") + interface InterfaceWithPath extends Jax { + @GET + void call() + } + + @Path("/abstract") + abstract class AbstractClassWithPath implements Jax { + @PUT + abstract void call() + } + + @Path("/child") + class ChildClassWithPath extends AbstractClassWithPath { + @POST + void call() {} + } +} diff --git a/dd-java-agent/instrumentation/jax-rs/src/test/groovy/JerseyTest.groovy b/dd-java-agent/instrumentation/jax-rs/src/test/groovy/JerseyTest.groovy new file mode 100644 index 0000000000..93ddef8e30 --- /dev/null +++ b/dd-java-agent/instrumentation/jax-rs/src/test/groovy/JerseyTest.groovy @@ -0,0 +1,33 @@ +import datadog.trace.agent.test.AgentTestRunner +import io.dropwizard.testing.junit.ResourceTestRule +import org.junit.ClassRule +import spock.lang.Shared + +class JerseyTest extends AgentTestRunner { + + static { + System.setProperty("dd.integration.jax-rs.enabled", "true") + } + + @Shared + @ClassRule + ResourceTestRule resources = ResourceTestRule.builder().addResource(new TestResource()).build() + + def "test resource"() { + setup: + // start a trace because the test doesn't go through any servlet or other instrumentation. + def scope = TEST_TRACER.buildSpan("test.span").startActive(true) + def response = resources.client().resource("/test/hello/bob").post(String) + scope.close() + + expect: + response == "Hello bob!" + TEST_WRITER.waitForTraces(1) + TEST_WRITER.size() == 1 + + def trace = TEST_WRITER.firstTrace() + def span = trace[0] + span.resourceName == "POST /test/hello/{name}" + span.tags["component"] == "jax-rs" + } +} diff --git a/dd-java-agent/instrumentation/jax-rs/src/test/java/TestResource.java b/dd-java-agent/instrumentation/jax-rs/src/test/java/TestResource.java new file mode 100644 index 0000000000..43b09ec2d4 --- /dev/null +++ b/dd-java-agent/instrumentation/jax-rs/src/test/java/TestResource.java @@ -0,0 +1,13 @@ +import javax.ws.rs.POST; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; + +// Originally had this as a groovy class but was getting some weird errors. +@Path("/test") +public class TestResource { + @POST + @Path("/hello/{name}") + public String addBook(@PathParam("name") final String name) { + return "Hello " + name + "!"; + } +} diff --git a/dd-java-agent/instrumentation/kafka-clients-0.11/kafka-clients-0.11.gradle b/dd-java-agent/instrumentation/kafka-clients-0.11/kafka-clients-0.11.gradle index 404aa8c8b0..f46c36bae2 100644 --- a/dd-java-agent/instrumentation/kafka-clients-0.11/kafka-clients-0.11.gradle +++ b/dd-java-agent/instrumentation/kafka-clients-0.11/kafka-clients-0.11.gradle @@ -25,5 +25,5 @@ dependencies { testCompile group: 'org.apache.kafka', name: 'kafka-clients', version: '0.11.0.0' testCompile group: 'org.springframework.kafka', name: 'spring-kafka', version: '1.3.3.RELEASE' testCompile group: 'org.springframework.kafka', name: 'spring-kafka-test', version: '1.3.3.RELEASE' - testCompile group: 'javax.xml.bind', name: 'jaxb-api', version: '2.3.0' + testCompile group: 'javax.xml.bind', name: 'jaxb-api', version: '2.2.3' } diff --git a/dd-java-agent/instrumentation/kafka-clients-0.11/src/test/groovy/KafkaClientTest.groovy b/dd-java-agent/instrumentation/kafka-clients-0.11/src/test/groovy/KafkaClientTest.groovy index b36de45d09..574e00c7a2 100644 --- a/dd-java-agent/instrumentation/kafka-clients-0.11/src/test/groovy/KafkaClientTest.groovy +++ b/dd-java-agent/instrumentation/kafka-clients-0.11/src/test/groovy/KafkaClientTest.groovy @@ -1,9 +1,6 @@ -import ch.qos.logback.classic.Level -import ch.qos.logback.classic.Logger import datadog.trace.agent.test.AgentTestRunner import org.apache.kafka.clients.consumer.ConsumerRecord import org.junit.ClassRule -import org.slf4j.LoggerFactory import org.springframework.kafka.core.DefaultKafkaConsumerFactory import org.springframework.kafka.core.DefaultKafkaProducerFactory import org.springframework.kafka.core.KafkaTemplate @@ -22,8 +19,6 @@ class KafkaClientTest extends AgentTestRunner { static final SHARED_TOPIC = "shared.topic" static { - ((Logger) LoggerFactory.getLogger(Logger.ROOT_LOGGER_NAME)).setLevel(Level.WARN) - ((Logger) LoggerFactory.getLogger("datadog")).setLevel(Level.DEBUG) System.setProperty("dd.integration.kafka.enabled", "true") } diff --git a/dd-java-agent/instrumentation/kafka-streams-0.11/kafka-streams-0.11.gradle b/dd-java-agent/instrumentation/kafka-streams-0.11/kafka-streams-0.11.gradle index 2b527c1de3..e742436da3 100644 --- a/dd-java-agent/instrumentation/kafka-streams-0.11/kafka-streams-0.11.gradle +++ b/dd-java-agent/instrumentation/kafka-streams-0.11/kafka-streams-0.11.gradle @@ -29,5 +29,5 @@ dependencies { testCompile group: 'org.apache.kafka', name: 'kafka-streams', version: '0.11.0.0' testCompile group: 'org.springframework.kafka', name: 'spring-kafka', version: '1.3.3.RELEASE' testCompile group: 'org.springframework.kafka', name: 'spring-kafka-test', version: '1.3.3.RELEASE' - testCompile group: 'javax.xml.bind', name: 'jaxb-api', version: '2.3.0' + testCompile group: 'javax.xml.bind', name: 'jaxb-api', version: '2.2.3' } diff --git a/dd-java-agent/instrumentation/kafka-streams-0.11/src/test/groovy/KafkaStreamsTest.groovy b/dd-java-agent/instrumentation/kafka-streams-0.11/src/test/groovy/KafkaStreamsTest.groovy index 3e71e50edd..4cfe2de2fc 100644 --- a/dd-java-agent/instrumentation/kafka-streams-0.11/src/test/groovy/KafkaStreamsTest.groovy +++ b/dd-java-agent/instrumentation/kafka-streams-0.11/src/test/groovy/KafkaStreamsTest.groovy @@ -1,7 +1,6 @@ import ch.qos.logback.classic.Level import ch.qos.logback.classic.Logger import datadog.trace.agent.test.AgentTestRunner -import io.opentracing.util.GlobalTracer import org.apache.kafka.clients.consumer.ConsumerRecord import org.apache.kafka.common.serialization.Serdes import org.apache.kafka.streams.KafkaStreams @@ -61,7 +60,7 @@ class KafkaStreamsTest extends AgentTestRunner { @Override void onMessage(ConsumerRecord record) { WRITER_PHASER.arriveAndAwaitAdvance() // ensure consistent ordering of traces - GlobalTracer.get().activeSpan().setTag("testing", 123) + TEST_TRACER.activeSpan().setTag("testing", 123) records.add(record) } }) @@ -80,7 +79,7 @@ class KafkaStreamsTest extends AgentTestRunner { @Override String apply(String textLine) { WRITER_PHASER.arriveAndAwaitAdvance() // ensure consistent ordering of traces - GlobalTracer.get().activeSpan().setTag("asdf", "testing") + TEST_TRACER.activeSpan().setTag("asdf", "testing") return textLine.toLowerCase() } }) diff --git a/dd-java-agent/src/test/resources/logback.xml b/dd-java-agent/src/test/resources/logback.xml index 59f0b9fa19..eeb933ffad 100644 --- a/dd-java-agent/src/test/resources/logback.xml +++ b/dd-java-agent/src/test/resources/logback.xml @@ -13,6 +13,6 @@ - + diff --git a/dd-java-agent/testing/src/main/java/datadog/trace/agent/test/AgentTestRunner.java b/dd-java-agent/testing/src/main/java/datadog/trace/agent/test/AgentTestRunner.java index f765fab94d..36047957ac 100644 --- a/dd-java-agent/testing/src/main/java/datadog/trace/agent/test/AgentTestRunner.java +++ b/dd-java-agent/testing/src/main/java/datadog/trace/agent/test/AgentTestRunner.java @@ -1,5 +1,7 @@ package datadog.trace.agent.test; +import ch.qos.logback.classic.Level; +import ch.qos.logback.classic.Logger; import datadog.opentracing.DDSpan; import datadog.opentracing.DDTracer; import datadog.opentracing.decorators.AbstractDecorator; @@ -12,10 +14,18 @@ import java.lang.instrument.ClassFileTransformer; import java.lang.instrument.Instrumentation; import java.util.List; import java.util.concurrent.Phaser; +import java.util.concurrent.atomic.AtomicInteger; +import lombok.extern.slf4j.Slf4j; import net.bytebuddy.agent.ByteBuddyAgent; +import net.bytebuddy.agent.builder.AgentBuilder; +import net.bytebuddy.description.type.TypeDescription; +import net.bytebuddy.dynamic.DynamicType; +import net.bytebuddy.utility.JavaModule; +import org.junit.After; import org.junit.AfterClass; import org.junit.Before; import org.junit.BeforeClass; +import org.slf4j.LoggerFactory; import org.spockframework.runtime.model.SpecMetadata; import spock.lang.Specification; @@ -34,6 +44,7 @@ import spock.lang.Specification; * in an initialized state. * */ +@Slf4j @SpecMetadata(filename = "AgentTestRunner.java", line = 0) public abstract class AgentTestRunner extends Specification { /** @@ -43,13 +54,18 @@ public abstract class AgentTestRunner extends Specification { */ public static final ListWriter TEST_WRITER; - private static final Tracer TEST_TRACER; + protected static final Tracer TEST_TRACER; + private static final AtomicInteger INSTRUMENTATION_ERROR_COUNT = new AtomicInteger(); + private static final Instrumentation instrumentation; private static ClassFileTransformer activeTransformer = null; protected static final Phaser WRITER_PHASER = new Phaser(); static { + ((Logger) LoggerFactory.getLogger(Logger.ROOT_LOGGER_NAME)).setLevel(Level.WARN); + ((Logger) LoggerFactory.getLogger("datadog")).setLevel(Level.DEBUG); + WRITER_PHASER.register(); TEST_WRITER = new ListWriter() { @@ -75,13 +91,22 @@ public abstract class AgentTestRunner extends Specification { if (null != activeTransformer) { throw new IllegalStateException("transformer already in place: " + activeTransformer); } - activeTransformer = AgentInstaller.installBytebuddyAgent(instrumentation); + + activeTransformer = + AgentInstaller.installBytebuddyAgent(instrumentation, new ErrorCountingListener()); TestUtils.registerOrReplaceGlobalTracer(TEST_TRACER); } @Before public void beforeTest() { TEST_WRITER.start(); + INSTRUMENTATION_ERROR_COUNT.set(0); + assert TEST_TRACER.activeSpan() == null; + } + + @After + public void afterTest() { + assert INSTRUMENTATION_ERROR_COUNT.get() == 0; } @AfterClass @@ -89,4 +114,45 @@ public abstract class AgentTestRunner extends Specification { instrumentation.removeTransformer(activeTransformer); activeTransformer = null; } + + private static class ErrorCountingListener implements AgentBuilder.Listener { + @Override + public void onDiscovery( + final String typeName, + final ClassLoader classLoader, + final JavaModule module, + final boolean loaded) {} + + @Override + public void onTransformation( + final TypeDescription typeDescription, + final ClassLoader classLoader, + final JavaModule module, + final boolean loaded, + final DynamicType dynamicType) {} + + @Override + public void onIgnored( + final TypeDescription typeDescription, + final ClassLoader classLoader, + final JavaModule module, + final boolean loaded) {} + + @Override + public void onError( + final String typeName, + final ClassLoader classLoader, + final JavaModule module, + final boolean loaded, + final Throwable throwable) { + INSTRUMENTATION_ERROR_COUNT.incrementAndGet(); + } + + @Override + public void onComplete( + final String typeName, + final ClassLoader classLoader, + final JavaModule module, + final boolean loaded) {} + } } diff --git a/dd-java-agent/testing/testing.gradle b/dd-java-agent/testing/testing.gradle index a91ff452a9..5f8de588cf 100644 --- a/dd-java-agent/testing/testing.gradle +++ b/dd-java-agent/testing/testing.gradle @@ -6,6 +6,7 @@ dependencies { compile deps.slf4j compile deps.opentracing compile deps.spock + compile deps.testLogging compile project(':dd-trace-ot') compile project(':dd-java-agent:tooling') diff --git a/dd-java-agent/tooling/src/main/java/datadog/trace/agent/tooling/AgentInstaller.java b/dd-java-agent/tooling/src/main/java/datadog/trace/agent/tooling/AgentInstaller.java index 0269f11372..05a95962bf 100644 --- a/dd-java-agent/tooling/src/main/java/datadog/trace/agent/tooling/AgentInstaller.java +++ b/dd-java-agent/tooling/src/main/java/datadog/trace/agent/tooling/AgentInstaller.java @@ -26,7 +26,8 @@ public class AgentInstaller { * @param inst Java Instrumentation used to install bytebuddy * @return the agent's class transformer */ - public static ResettableClassFileTransformer installBytebuddyAgent(final Instrumentation inst) { + public static ResettableClassFileTransformer installBytebuddyAgent( + final Instrumentation inst, final AgentBuilder.Listener... listeners) { AgentBuilder agentBuilder = new AgentBuilder.Default() .disableClassFormatChanges() @@ -53,6 +54,9 @@ public class AgentInstaller { .or( classLoaderWithName( "org.codehaus.groovy.runtime.callsite.CallSiteClassLoader"))); + for (final AgentBuilder.Listener listener : listeners) { + agentBuilder = agentBuilder.with(listener); + } int numInstrumenters = 0; for (final Instrumenter instrumenter : ServiceLoader.load(Instrumenter.class)) { log.debug("Loading instrumentation {}", instrumenter); diff --git a/dd-trace-ot/src/main/java/datadog/trace/common/writer/ListWriter.java b/dd-trace-ot/src/main/java/datadog/trace/common/writer/ListWriter.java index cd92de12cb..ec77537c8b 100644 --- a/dd-trace-ot/src/main/java/datadog/trace/common/writer/ListWriter.java +++ b/dd-trace-ot/src/main/java/datadog/trace/common/writer/ListWriter.java @@ -7,6 +7,8 @@ import java.util.List; import java.util.Map; import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; /** List writer used by tests mostly */ public class ListWriter extends CopyOnWriteArrayList> implements Writer { @@ -30,7 +32,7 @@ public class ListWriter extends CopyOnWriteArrayList> implements Wr } } - public void waitForTraces(final int number) throws InterruptedException { + public void waitForTraces(final int number) throws InterruptedException, TimeoutException { final CountDownLatch latch = new CountDownLatch(number); synchronized (latches) { if (size() >= number) { @@ -38,7 +40,9 @@ public class ListWriter extends CopyOnWriteArrayList> implements Wr } latches.add(latch); } - latch.await(); + if (!latch.await(5, TimeUnit.SECONDS)) { + throw new TimeoutException("Timeout waiting for " + number + " trace(s)."); + } } @Override diff --git a/settings.gradle b/settings.gradle index 1184c556cf..2b77c7156f 100644 --- a/settings.gradle +++ b/settings.gradle @@ -11,6 +11,7 @@ include ':dd-trace-api' include ':dd-java-agent:instrumentation:apache-httpclient-4.3' include ':dd-java-agent:instrumentation:aws-sdk' include ':dd-java-agent:instrumentation:datastax-cassandra-3.2' +include ':dd-java-agent:instrumentation:jax-rs' include ':dd-java-agent:instrumentation:jdbc' include ':dd-java-agent:instrumentation:jms-1' include ':dd-java-agent:instrumentation:jms-2'