diff --git a/dd-java-agent-ittests/dd-java-agent-ittests.gradle b/dd-java-agent-ittests/dd-java-agent-ittests.gradle index 9196577168..524b4e1945 100644 --- a/dd-java-agent-ittests/dd-java-agent-ittests.gradle +++ b/dd-java-agent-ittests/dd-java-agent-ittests.gradle @@ -60,8 +60,38 @@ test { if (project.hasProperty("disableShadowRelocate") && disableShadowRelocate) { exclude 'com/datadoghq/agent/ShadowPackageRenamingTest.class' } + + useJUnit { + excludeCategories 'com.datadoghq.agent.integration.ExpensiveTest' + } } +task expensiveTest(type: Test) { + jvmArgs "-Ddd.trace.configurationFile=${project.buildDir}/resources/test/dd-trace.yaml" + jvmArgs "-Ddd.slf4j.simpleLogger.defaultLogLevel=debug" + jvmArgs "-Dorg.slf4j.simpleLogger.defaultLogLevel=debug" + jvmArgs "-Ddd.deps.org.jboss.byteman.verbose=true" + jvmArgs "-Dorg.jboss.byteman.verbose=true" + + doFirst { + // Defining here to allow jacoco to be first on the command line. + jvmArgs "-javaagent:${project(':dd-java-agent').tasks.shadowJar.archivePath}" + } + + testLogging { + events "started" + } + + if (project.hasProperty("disableShadowRelocate") && disableShadowRelocate) { + exclude 'com/datadoghq/agent/ShadowPackageRenamingTest.class' + } + + useJUnit { + includeCategories 'com.datadoghq.agent.integration.ExpensiveTest' + } +} +test.finalizedBy expensiveTest + test.dependsOn project(':dd-java-agent').shadowJar parent.subprojects.collect { it.tasks.withType(Test) } each { diff --git a/dd-java-agent-ittests/src/test/java/com/datadoghq/agent/integration/CassandraIntegrationTest.java b/dd-java-agent-ittests/src/test/java/com/datadoghq/agent/integration/CassandraIntegrationTest.java index d31f4439d8..b15b7ed897 100644 --- a/dd-java-agent-ittests/src/test/java/com/datadoghq/agent/integration/CassandraIntegrationTest.java +++ b/dd-java-agent-ittests/src/test/java/com/datadoghq/agent/integration/CassandraIntegrationTest.java @@ -12,8 +12,10 @@ import org.cassandraunit.utils.EmbeddedCassandraServerHelper; import org.junit.After; import org.junit.Before; import org.junit.Test; +import org.junit.experimental.categories.Category; /** Created by gpolaert on 6/2/17. */ +@Category(ExpensiveTest.class) public class CassandraIntegrationTest { @Before diff --git a/dd-java-agent-ittests/src/test/java/com/datadoghq/agent/integration/ExpensiveTest.java b/dd-java-agent-ittests/src/test/java/com/datadoghq/agent/integration/ExpensiveTest.java new file mode 100644 index 0000000000..2349b92d4e --- /dev/null +++ b/dd-java-agent-ittests/src/test/java/com/datadoghq/agent/integration/ExpensiveTest.java @@ -0,0 +1,3 @@ +package com.datadoghq.agent.integration; + +interface ExpensiveTest {} diff --git a/dd-java-agent/dd-java-agent.gradle b/dd-java-agent/dd-java-agent.gradle index ae1e24c3f1..f94a5671d5 100644 --- a/dd-java-agent/dd-java-agent.gradle +++ b/dd-java-agent/dd-java-agent.gradle @@ -18,9 +18,13 @@ whitelistedInstructionClasses += whitelistedBranchClasses += [ dependencies { compile project(':dd-trace') + compile project(':dd-java-agent:tooling') compile project(':dd-trace-annotations') - compile group: 'net.bytebuddy', name: 'byte-buddy', version: '1.7.6' + + compile project(':dd-java-agent:integrations:spring-web') + + compile deps.bytebuddy compile group: 'org.jboss.byteman', name: 'byteman', version: '3.0.10' compile group: 'com.google.auto.service', name: 'auto-service', version: '1.0-rc3' diff --git a/dd-java-agent/integrations/spring-web/spring-web.gradle b/dd-java-agent/integrations/spring-web/spring-web.gradle new file mode 100644 index 0000000000..2ca83728bd --- /dev/null +++ b/dd-java-agent/integrations/spring-web/spring-web.gradle @@ -0,0 +1,29 @@ +//apply plugin: 'version-scan' +// +//versionScan { +// group = 'org.springframework' +// module = 'spring-webmvc' +// legacyModule = "servlet-api" +// versions = "[3.0,)" +// verifyPresent = [ +// "javax.servlet.AsyncEvent" : null, +// "javax.servlet.AsyncListener": null, +// ] +//} + +apply from: "${rootDir}/gradle/java.gradle" + +dependencies { + compileOnly group: 'org.springframework', name: 'spring-webmvc', version: '4.0.0.RELEASE' + compileOnly group: 'javax.servlet', name: 'javax.servlet-api', version: '3.1.0' +// compileOnly group: 'org.springframework', name: 'spring-webmvc', version: '2.5.6' +// compileOnly group: 'javax.servlet', name: 'servlet-api', version: '2.4' + + compile project(':dd-trace') + compile project(':dd-java-agent:tooling') + + compile deps.bytebuddy + compile deps.opentracing + + compile group: 'com.google.auto.service', name: 'auto-service', version: '1.0-rc3' +} diff --git a/dd-java-agent/integrations/spring-web/src/main/java/dd/inst/springweb/SpringWebInstrumentation.java b/dd-java-agent/integrations/spring-web/src/main/java/dd/inst/springweb/SpringWebInstrumentation.java new file mode 100644 index 0000000000..2e19e4bac4 --- /dev/null +++ b/dd-java-agent/integrations/spring-web/src/main/java/dd/inst/springweb/SpringWebInstrumentation.java @@ -0,0 +1,59 @@ +package dd.inst.springweb; + +import static net.bytebuddy.matcher.ElementMatchers.hasSuperType; +import static net.bytebuddy.matcher.ElementMatchers.isInterface; +import static net.bytebuddy.matcher.ElementMatchers.isMethod; +import static net.bytebuddy.matcher.ElementMatchers.isPublic; +import static net.bytebuddy.matcher.ElementMatchers.nameStartsWith; +import static net.bytebuddy.matcher.ElementMatchers.named; +import static net.bytebuddy.matcher.ElementMatchers.not; +import static net.bytebuddy.matcher.ElementMatchers.takesArgument; + +import com.datadoghq.trace.DDTags; +import com.google.auto.service.AutoService; +import dd.trace.Instrumenter; +import io.opentracing.ActiveSpan; +import io.opentracing.util.GlobalTracer; +import java.sql.PreparedStatement; +import java.util.Map; +import java.util.WeakHashMap; +import javax.servlet.http.HttpServletRequest; +import net.bytebuddy.agent.builder.AgentBuilder; +import net.bytebuddy.asm.Advice; +import org.springframework.web.servlet.HandlerMapping; + +@AutoService(Instrumenter.class) +public final class SpringWebInstrumentation implements Instrumenter { + public static final Map preparedStatements = new WeakHashMap<>(); + + @Override + public AgentBuilder instrument(final AgentBuilder agentBuilder) { + return agentBuilder + .type( + not(isInterface()) + .and(hasSuperType(named("org.springframework.web.servlet.HandlerAdapter")))) + .transform( + new AgentBuilder.Transformer.ForAdvice() + .advice( + isMethod() + .and(isPublic()) + .and(nameStartsWith("handle")) + .and(takesArgument(0, named("javax.servlet.http.HttpServletRequest"))), + SpringWebAdvice.class.getName())); + } + + public static class SpringWebAdvice { + + @Advice.OnMethodEnter + public static void nameResource(@Advice.Argument(0) final HttpServletRequest request) { + final ActiveSpan span = GlobalTracer.get().activeSpan(); + if (span != null) { + final String method = request.getMethod(); + final String bestMatchingPattern = + request.getAttribute(HandlerMapping.BEST_MATCHING_PATTERN_ATTRIBUTE).toString(); + final String resourceName = method + " " + bestMatchingPattern; + span.setTag(DDTags.RESOURCE_NAME, resourceName); + } + } + } +} diff --git a/dd-java-agent/src/main/java/com/datadoghq/agent/TracingAgent.java b/dd-java-agent/src/main/java/com/datadoghq/agent/TracingAgent.java index cc1e95c062..1383808218 100644 --- a/dd-java-agent/src/main/java/com/datadoghq/agent/TracingAgent.java +++ b/dd-java-agent/src/main/java/com/datadoghq/agent/TracingAgent.java @@ -23,7 +23,7 @@ import static net.bytebuddy.matcher.ElementMatchers.isBootstrapClassLoader; import static net.bytebuddy.matcher.ElementMatchers.nameContains; import static net.bytebuddy.matcher.ElementMatchers.nameStartsWith; -import com.datadoghq.agent.instrumentation.Instrumenter; +import dd.trace.Instrumenter; import java.lang.instrument.Instrumentation; import java.util.ServiceLoader; import lombok.extern.slf4j.Slf4j; @@ -71,6 +71,9 @@ public class TracingAgent { .with(AgentBuilder.RedefinitionStrategy.RETRANSFORMATION) .with(new Listener()) .ignore(nameStartsWith("com.datadoghq.agent.integration")) + .or(nameStartsWith("dd.trace")) + .or(nameStartsWith("dd.inst")) + .or(nameStartsWith("dd.deps")) .or(nameStartsWith("java.")) .or(nameStartsWith("com.sun.")) .or(nameStartsWith("sun.")) diff --git a/dd-java-agent/src/main/java/com/datadoghq/agent/instrumentation/annotation/TraceAnnotationInstrumentation.java b/dd-java-agent/src/main/java/com/datadoghq/agent/instrumentation/annotation/TraceAnnotationInstrumentation.java index 6c29b7485b..6b222cf77b 100644 --- a/dd-java-agent/src/main/java/com/datadoghq/agent/instrumentation/annotation/TraceAnnotationInstrumentation.java +++ b/dd-java-agent/src/main/java/com/datadoghq/agent/instrumentation/annotation/TraceAnnotationInstrumentation.java @@ -4,9 +4,9 @@ import static net.bytebuddy.matcher.ElementMatchers.declaresMethod; import static net.bytebuddy.matcher.ElementMatchers.hasSuperType; import static net.bytebuddy.matcher.ElementMatchers.isAnnotatedWith; -import com.datadoghq.agent.instrumentation.Instrumenter; import com.datadoghq.trace.Trace; import com.google.auto.service.AutoService; +import dd.trace.Instrumenter; import io.opentracing.ActiveSpan; import io.opentracing.tag.Tags; import io.opentracing.util.GlobalTracer; diff --git a/dd-java-agent/src/main/java/com/datadoghq/agent/instrumentation/jdbc/ConnectionInstrumentation.java b/dd-java-agent/src/main/java/com/datadoghq/agent/instrumentation/jdbc/ConnectionInstrumentation.java index 6284ff5163..17bd26f754 100644 --- a/dd-java-agent/src/main/java/com/datadoghq/agent/instrumentation/jdbc/ConnectionInstrumentation.java +++ b/dd-java-agent/src/main/java/com/datadoghq/agent/instrumentation/jdbc/ConnectionInstrumentation.java @@ -8,8 +8,8 @@ import static net.bytebuddy.matcher.ElementMatchers.not; import static net.bytebuddy.matcher.ElementMatchers.returns; import static net.bytebuddy.matcher.ElementMatchers.takesArgument; -import com.datadoghq.agent.instrumentation.Instrumenter; import com.google.auto.service.AutoService; +import dd.trace.Instrumenter; import java.sql.Connection; import java.sql.PreparedStatement; import java.util.Map; diff --git a/dd-java-agent/src/main/java/com/datadoghq/agent/instrumentation/jdbc/DriverInstrumentation.java b/dd-java-agent/src/main/java/com/datadoghq/agent/instrumentation/jdbc/DriverInstrumentation.java index 21d470e7f5..9bdab13267 100644 --- a/dd-java-agent/src/main/java/com/datadoghq/agent/instrumentation/jdbc/DriverInstrumentation.java +++ b/dd-java-agent/src/main/java/com/datadoghq/agent/instrumentation/jdbc/DriverInstrumentation.java @@ -6,8 +6,8 @@ import static net.bytebuddy.matcher.ElementMatchers.named; import static net.bytebuddy.matcher.ElementMatchers.not; import static net.bytebuddy.matcher.ElementMatchers.takesArguments; -import com.datadoghq.agent.instrumentation.Instrumenter; import com.google.auto.service.AutoService; +import dd.trace.Instrumenter; import java.sql.Connection; import java.sql.Driver; import java.util.Map; diff --git a/dd-java-agent/src/main/java/com/datadoghq/agent/instrumentation/jdbc/PreparedStatementInstrumentation.java b/dd-java-agent/src/main/java/com/datadoghq/agent/instrumentation/jdbc/PreparedStatementInstrumentation.java index 82e74452e1..36a4921c54 100644 --- a/dd-java-agent/src/main/java/com/datadoghq/agent/instrumentation/jdbc/PreparedStatementInstrumentation.java +++ b/dd-java-agent/src/main/java/com/datadoghq/agent/instrumentation/jdbc/PreparedStatementInstrumentation.java @@ -8,9 +8,9 @@ import static net.bytebuddy.matcher.ElementMatchers.named; import static net.bytebuddy.matcher.ElementMatchers.not; import static net.bytebuddy.matcher.ElementMatchers.takesArguments; -import com.datadoghq.agent.instrumentation.Instrumenter; import com.datadoghq.trace.DDTags; import com.google.auto.service.AutoService; +import dd.trace.Instrumenter; import io.opentracing.ActiveSpan; import io.opentracing.NoopActiveSpanSource; import io.opentracing.tag.Tags; diff --git a/dd-java-agent/src/main/java/com/datadoghq/agent/instrumentation/jdbc/StatementInstrumentation.java b/dd-java-agent/src/main/java/com/datadoghq/agent/instrumentation/jdbc/StatementInstrumentation.java index 21fdcd4c1f..cb92fca403 100644 --- a/dd-java-agent/src/main/java/com/datadoghq/agent/instrumentation/jdbc/StatementInstrumentation.java +++ b/dd-java-agent/src/main/java/com/datadoghq/agent/instrumentation/jdbc/StatementInstrumentation.java @@ -8,9 +8,9 @@ import static net.bytebuddy.matcher.ElementMatchers.named; import static net.bytebuddy.matcher.ElementMatchers.not; import static net.bytebuddy.matcher.ElementMatchers.takesArgument; -import com.datadoghq.agent.instrumentation.Instrumenter; import com.datadoghq.trace.DDTags; import com.google.auto.service.AutoService; +import dd.trace.Instrumenter; import io.opentracing.ActiveSpan; import io.opentracing.NoopActiveSpanSource; import io.opentracing.tag.Tags; diff --git a/dd-java-agent/src/main/java/com/datadoghq/agent/instrumentation/Instrumenter.java b/dd-java-agent/tooling/src/main/java/dd/trace/Instrumenter.java similarity index 75% rename from dd-java-agent/src/main/java/com/datadoghq/agent/instrumentation/Instrumenter.java rename to dd-java-agent/tooling/src/main/java/dd/trace/Instrumenter.java index 5348b90523..70df3b6e8b 100644 --- a/dd-java-agent/src/main/java/com/datadoghq/agent/instrumentation/Instrumenter.java +++ b/dd-java-agent/tooling/src/main/java/dd/trace/Instrumenter.java @@ -1,4 +1,4 @@ -package com.datadoghq.agent.instrumentation; +package dd.trace; import net.bytebuddy.agent.builder.AgentBuilder; diff --git a/dd-java-agent/tooling/tooling.gradle b/dd-java-agent/tooling/tooling.gradle new file mode 100644 index 0000000000..0ca4a8c4b8 --- /dev/null +++ b/dd-java-agent/tooling/tooling.gradle @@ -0,0 +1,5 @@ +apply from: "${rootDir}/gradle/java.gradle" + +dependencies { + compile deps.bytebuddy +} diff --git a/gradle/dependencies.gradle b/gradle/dependencies.gradle index 83a545fde9..d5964610c7 100644 --- a/gradle/dependencies.gradle +++ b/gradle/dependencies.gradle @@ -29,7 +29,8 @@ ext { dependencies.create(group: 'com.fasterxml.jackson.core', name: 'jackson-databind', version: version.jackson), dependencies.create(group: 'com.fasterxml.jackson.dataformat', name: 'jackson-dataformat-yaml', version: version.jackson), ], - + bytebuddy : dependencies.create(group: 'net.bytebuddy', name: 'byte-buddy', version: '1.7.6'), + // Testing spock : dependencies.create("org.spockframework:spock-core:${version.spock}", { exclude group: "org.codehaus.groovy", module: "groovy-all" diff --git a/settings.gradle b/settings.gradle index c5863ce952..fc91598158 100644 --- a/settings.gradle +++ b/settings.gradle @@ -2,6 +2,7 @@ rootProject.name = 'dd-trace-java' include ':dd-trace' include ':dd-java-agent' +include ':dd-java-agent:tooling' include ':dd-java-agent-ittests' include ':dd-trace-examples:async-tracing' include ':dd-trace-examples:dropwizard-mongo-client' @@ -21,6 +22,7 @@ include ':dd-java-agent:integrations:mongo-async' include ':dd-java-agent:integrations:okhttp' include ':dd-java-agent:integrations:servlet-2' include ':dd-java-agent:integrations:servlet-3' +include ':dd-java-agent:integrations:spring-web' def setBuildFile(project) { project.buildFileName = "${project.name}.gradle"