diff --git a/.circleci/config.yml b/.circleci/config.yml index 69581c64f8..b9eee3e469 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -187,8 +187,8 @@ jobs: - dd-trace-java-version-scan - run: - name: Verify Version Scan - command: ./gradlew verifyVersionScan --parallel --stacktrace --no-daemon --max-workers=6 + name: Verify Version Scan and Muzzle + command: ./gradlew verifyVersionScan muzzle --parallel --stacktrace --no-daemon --max-workers=6 - save_cache: key: dd-trace-java-version-scan-{{ checksum "dd-trace-java.gradle" }} diff --git a/buildSrc/src/main/groovy/MuzzleExtension.groovy b/buildSrc/src/main/groovy/MuzzleExtension.groovy new file mode 100644 index 0000000000..d8af853c9e --- /dev/null +++ b/buildSrc/src/main/groovy/MuzzleExtension.groovy @@ -0,0 +1,4 @@ +class MuzzleExtension { + String group + String module +} diff --git a/buildSrc/src/main/groovy/MuzzlePlugin.groovy b/buildSrc/src/main/groovy/MuzzlePlugin.groovy new file mode 100644 index 0000000000..3c85179a39 --- /dev/null +++ b/buildSrc/src/main/groovy/MuzzlePlugin.groovy @@ -0,0 +1,58 @@ +import org.gradle.api.Plugin +import org.gradle.api.Project + +import java.lang.reflect.Method + +/** + * muzzle task plugin which runs muzzle validation against an instrumentation's compile-time dependencies. + * + *

TODO: merge this with version scan + */ +class MuzzlePlugin implements Plugin { + @Override + void apply(Project project) { + def bootstrapProject = project.rootProject.getChildProjects().get('dd-java-agent').getChildProjects().get('agent-bootstrap') + def toolingProject = project.rootProject.getChildProjects().get('dd-java-agent').getChildProjects().get('agent-tooling') + project.extensions.create("muzzle", MuzzleExtension) + def muzzle = project.task('muzzle') { + group = 'Muzzle' + description = "Run instrumentation muzzle on compile time dependencies" + doLast { + List userUrls = new ArrayList<>() + project.getLogger().info("Creating user classpath for: " + project.getName()) + for (File f : project.configurations.compileOnly.getFiles()) { + project.getLogger().info( '--' + f) + userUrls.add(f.toURI().toURL()) + } + for (File f : bootstrapProject.sourceSets.main.runtimeClasspath.getFiles()) { + project.getLogger().info( '--' + f) + userUrls.add(f.toURI().toURL()) + } + final ClassLoader userCL = new URLClassLoader(userUrls.toArray(new URL[0]), (ClassLoader) null) + + project.getLogger().info("Creating dd classpath for: " + project.getName()) + Set ddUrls = new HashSet<>() + for (File f : toolingProject.sourceSets.main.runtimeClasspath.getFiles()) { + project.getLogger().info( '--' + f) + ddUrls.add(f.toURI().toURL()) + } + for(File f : project.sourceSets.main.runtimeClasspath.getFiles()) { + project.getLogger().info( '--' + f) + ddUrls.add(f.toURI().toURL()) + } + + final ClassLoader agentCL = new URLClassLoader(ddUrls.toArray(new URL[0]), (ClassLoader) null) + // find all instrumenters, get muzzle, and assert + Method assertionMethod = agentCL.loadClass('datadog.trace.agent.tooling.muzzle.MuzzleVersionScanPlugin') + .getMethod('assertInstrumentationNotMuzzled', ClassLoader.class) + assertionMethod.invoke(null, userCL) + } + } + // project.tasks.muzzle.dependsOn(bootstrapProject.tasks.shadowJar) + project.tasks.muzzle.dependsOn(bootstrapProject.tasks.compileJava) + project.tasks.muzzle.dependsOn(toolingProject.tasks.compileJava) + project.afterEvaluate { + project.tasks.muzzle.dependsOn(project.tasks.compileJava) + } + } +} diff --git a/buildSrc/src/main/resources/META-INF/gradle-plugins/muzzle.properties b/buildSrc/src/main/resources/META-INF/gradle-plugins/muzzle.properties new file mode 100644 index 0000000000..61b482e54a --- /dev/null +++ b/buildSrc/src/main/resources/META-INF/gradle-plugins/muzzle.properties @@ -0,0 +1 @@ +implementation-class=MuzzlePlugin diff --git a/dd-java-agent-ittests/src/test/groovy/datadog/trace/agent/integration/muzzle/MuzzleBytecodeTransformTest.groovy b/dd-java-agent-ittests/src/test/groovy/datadog/trace/agent/integration/muzzle/MuzzleBytecodeTransformTest.groovy index 1e2bc31284..0269047eb5 100644 --- a/dd-java-agent-ittests/src/test/groovy/datadog/trace/agent/integration/muzzle/MuzzleBytecodeTransformTest.groovy +++ b/dd-java-agent-ittests/src/test/groovy/datadog/trace/agent/integration/muzzle/MuzzleBytecodeTransformTest.groovy @@ -8,13 +8,17 @@ import spock.lang.Specification class MuzzleBytecodeTransformTest extends Specification { - /* def "muzzle fields added to all instrumentation"() { setup: List unMuzzledClasses = [] List nonLazyFields = [] List unInitFields = [] - for (final Object instrumenter : ServiceLoader.load(IntegrationTestUtils.getAgentClassLoader().loadClass("datadog.trace.agent.tooling.Instrumenter"), IntegrationTestUtils.getAgentClassLoader())) { + for (Object instrumenter : ServiceLoader.load(IntegrationTestUtils.getAgentClassLoader().loadClass("datadog.trace.agent.tooling.Instrumenter"), IntegrationTestUtils.getAgentClassLoader())) { + if (instrumenter.getClass().getName().endsWith("TraceConfigInstrumentation")) { + // TraceConfigInstrumentation doesn't do muzzle checks + // check on TracerClassInstrumentation instead + instrumenter = IntegrationTestUtils.getAgentClassLoader().loadClass(instrumenter.getClass().getName() + '$TracerClassInstrumentation').newInstance() + } Field f Method m try { @@ -45,6 +49,5 @@ class MuzzleBytecodeTransformTest extends Specification { nonLazyFields == [] unInitFields == [] } - */ } diff --git a/dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/AgentInstaller.java b/dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/AgentInstaller.java index 685d88e9ec..3a9aa0be71 100644 --- a/dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/AgentInstaller.java +++ b/dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/AgentInstaller.java @@ -8,8 +8,6 @@ import static net.bytebuddy.matcher.ElementMatchers.nameStartsWith; import static net.bytebuddy.matcher.ElementMatchers.named; import static net.bytebuddy.matcher.ElementMatchers.not; -import datadog.trace.agent.tooling.muzzle.Reference.Mismatch; -import datadog.trace.agent.tooling.muzzle.ReferenceMatcher.MismatchException; import java.lang.instrument.Instrumentation; import java.util.ServiceLoader; import lombok.extern.slf4j.Slf4j; @@ -91,19 +89,11 @@ public class AgentInstaller { final JavaModule module, final boolean loaded, final Throwable throwable) { - if (throwable instanceof MismatchException) { - final MismatchException mismatchException = (MismatchException) throwable; - log.debug("{}", mismatchException.getMessage()); - for (final Mismatch mismatch : mismatchException.getMismatches()) { - log.debug("--{}", mismatch); - } - } else { - log.debug( - "Failed to handle {} for transformation on classloader {}: {}", - typeName, - classLoader, - throwable.getMessage()); - } + log.debug( + "Failed to handle {} for transformation on classloader {}: {}", + typeName, + classLoader, + throwable.getMessage()); } @Override diff --git a/dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/Instrumenter.java b/dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/Instrumenter.java index 6003586367..06f65dac34 100644 --- a/dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/Instrumenter.java +++ b/dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/Instrumenter.java @@ -3,14 +3,19 @@ package datadog.trace.agent.tooling; import static datadog.trace.agent.tooling.Utils.getConfigEnabled; import static net.bytebuddy.matcher.ElementMatchers.any; +import datadog.trace.agent.tooling.muzzle.Reference; +import datadog.trace.agent.tooling.muzzle.ReferenceMatcher; +import java.security.ProtectionDomain; import java.util.Arrays; import java.util.HashSet; +import java.util.List; import java.util.Map; import java.util.Set; import lombok.extern.slf4j.Slf4j; import net.bytebuddy.agent.builder.AgentBuilder; import net.bytebuddy.description.type.TypeDescription; import net.bytebuddy.matcher.ElementMatcher; +import net.bytebuddy.utility.JavaModule; /** * Built-in bytebuddy-based instrumentation for the datadog javaagent. @@ -42,11 +47,13 @@ public interface Instrumenter { @Slf4j abstract class Default implements Instrumenter { private final Set instrumentationNames; + private final String instrumentationPrimaryName; protected final boolean enabled; public Default(final String instrumentationName, final String... additionalNames) { this.instrumentationNames = new HashSet<>(Arrays.asList(additionalNames)); instrumentationNames.add(instrumentationName); + instrumentationPrimaryName = instrumentationName; // If default is enabled, we want to enable individually, // if default is disabled, we want to disable individually. @@ -74,6 +81,35 @@ public interface Instrumenter { AgentBuilder.Identified.Extendable advice = agentBuilder .type(typeMatcher(), classLoaderMatcher()) + .and( + new AgentBuilder.RawMatcher() { + @Override + public boolean matches( + TypeDescription typeDescription, + ClassLoader classLoader, + JavaModule module, + Class classBeingRedefined, + ProtectionDomain protectionDomain) { + // Optimization: calling getInstrumentationMuzzle() inside this method prevents unnecessary loading of muzzle references during agentBuilder setup. + final ReferenceMatcher muzzle = getInstrumentationMuzzle(); + if (null != muzzle) { + List mismatches = + muzzle.getMismatchedReferenceSources(classLoader); + if (mismatches.size() > 0) { + log.debug( + "Instrumentation muzzled: {} -- {} on {}", + instrumentationPrimaryName, + this.getClass().getName(), + classLoader); + } + for (Reference.Mismatch mismatch : mismatches) { + log.debug("-- {}", mismatch); + } + return mismatches.size() == 0; + } + return true; + } + }) .transform(DDTransformers.defaultTransformers()); final String[] helperClassNames = helperClassNames(); if (helperClassNames.length > 0) { @@ -85,6 +121,15 @@ public interface Instrumenter { return advice.asDecorator(); } + /** + * This method is implemented dynamically by compile-time bytecode transformations. + * + *

{@see datadog.trace.agent.tooling.muzzle.MuzzleGradlePlugin} + */ + protected ReferenceMatcher getInstrumentationMuzzle() { + return null; + } + @Override public String[] helperClassNames() { return new String[0]; @@ -105,11 +150,13 @@ public interface Instrumenter { return getConfigEnabled("dd.integrations.enabled", true); } - protected static String getPropOrEnv(final String name) { + // TODO: move common config helpers to Utils + + public static String getPropOrEnv(final String name) { return System.getProperty(name, System.getenv(propToEnvName(name))); } - private static String propToEnvName(final String name) { + public static String propToEnvName(final String name) { return name.toUpperCase().replace(".", "_"); } } diff --git a/dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/muzzle/MuzzleGradlePlugin.java b/dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/muzzle/MuzzleGradlePlugin.java index 4e5d83aa5c..ebaa6b7dfb 100644 --- a/dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/muzzle/MuzzleGradlePlugin.java +++ b/dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/muzzle/MuzzleGradlePlugin.java @@ -6,44 +6,24 @@ import net.bytebuddy.description.type.TypeDefinition; import net.bytebuddy.description.type.TypeDescription; import net.bytebuddy.dynamic.DynamicType.Builder; +/** Bytebuddy gradle plugin which creates muzzle-references at compile time. */ public class MuzzleGradlePlugin implements Plugin { - // TODO: - // - Optimizations - // - Cache safe and unsafe classloaders - // - Do reference generation at compile time - // - lazy-load reference muzzle field - // - Additional references to check - // - Fields - // - methods - // - visit annotations - // - visit parameter types - // - visit method instructions - // - method invoke type - // - access flags (including implicit package-private) - // - supertypes - // - Misc - // - Also match interfaces which extend Instrumenter - // - Expose config instead of hardcoding datadog namespace (or reconfigure classpath) - // - Run muzzle in matching phase (may require a rewrite of the instrumentation api) - // - Documentation - - private static final TypeDescription InstrumenterTypeDesc = - new TypeDescription.ForLoadedType(Instrumenter.class); + private static final TypeDescription DefaultInstrumenterTypeDesc = + new TypeDescription.ForLoadedType(Instrumenter.Default.class); @Override public boolean matches(final TypeDescription target) { - // AutoService annotation is not retained at runtime. Check for instrumenter supertype + // AutoService annotation is not retained at runtime. Check for Instrumenter.Default supertype boolean isInstrumenter = false; - TypeDefinition instrumenter = target; + TypeDefinition instrumenter = null == target ? null : target.getSuperClass(); while (instrumenter != null) { - if (instrumenter.getInterfaces().contains(InstrumenterTypeDesc)) { + if (instrumenter.equals(DefaultInstrumenterTypeDesc)) { isInstrumenter = true; break; } instrumenter = instrumenter.getSuperClass(); } - // return isInstrumenter; - return false; + return isInstrumenter; } @Override @@ -51,6 +31,7 @@ public class MuzzleGradlePlugin implements Plugin { return builder.visit(new MuzzleVisitor()); } + /** Compile-time Optimization used by gradle buildscripts. */ public static class NoOp implements Plugin { @Override public boolean matches(final TypeDescription target) { diff --git a/dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/muzzle/MuzzleVersionScanPlugin.java b/dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/muzzle/MuzzleVersionScanPlugin.java new file mode 100644 index 0000000000..f6b37051cc --- /dev/null +++ b/dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/muzzle/MuzzleVersionScanPlugin.java @@ -0,0 +1,86 @@ +package datadog.trace.agent.tooling.muzzle; + +import datadog.trace.agent.tooling.HelperInjector; +import datadog.trace.agent.tooling.Instrumenter; +import java.lang.reflect.Method; +import java.util.List; +import java.util.ServiceLoader; + +/** + * Entry point for muzzle version scan gradle plugin. + * + *

For each instrumenter on the classpath, run muzzle validation and throw an exception if any + * mismatches are detected. + * + *

Additionally, after a successful muzzle validation run each instrumenter's helper injector. + */ +public class MuzzleVersionScanPlugin { + public static void assertInstrumentationNotMuzzled(ClassLoader cl) throws Exception { + // muzzle validate all instrumenters + for (Instrumenter instrumenter : + ServiceLoader.load(Instrumenter.class, MuzzleGradlePlugin.class.getClassLoader())) { + if (instrumenter.getClass().getName().endsWith("TraceConfigInstrumentation")) { + // TraceConfigInstrumentation doesn't do muzzle checks + // check on TracerClassInstrumentation instead + instrumenter = + (Instrumenter) + MuzzleGradlePlugin.class + .getClassLoader() + .loadClass(instrumenter.getClass().getName() + "$TracerClassInstrumentation") + .getDeclaredConstructor() + .newInstance(); + } + Method m = null; + try { + m = instrumenter.getClass().getDeclaredMethod("getInstrumentationMuzzle"); + m.setAccessible(true); + ReferenceMatcher muzzle = (ReferenceMatcher) m.invoke(instrumenter); + List mismatches = muzzle.getMismatchedReferenceSources(cl); + if (mismatches.size() > 0) { + System.err.println( + "FAILED MUZZLE VALIDATION: " + instrumenter.getClass().getName() + " mismatches:"); + for (Reference.Mismatch mismatch : mismatches) { + System.err.println("-- " + mismatch); + } + throw new RuntimeException("Instrumentation failed Muzzle validation"); + } + } finally { + if (null != m) { + m.setAccessible(false); + } + } + } + // run helper injector on all instrumenters + for (Instrumenter instrumenter : + ServiceLoader.load(Instrumenter.class, MuzzleGradlePlugin.class.getClassLoader())) { + if (instrumenter.getClass().getName().endsWith("TraceConfigInstrumentation")) { + // TraceConfigInstrumentation doesn't do muzzle checks + // check on TracerClassInstrumentation instead + instrumenter = + (Instrumenter) + MuzzleGradlePlugin.class + .getClassLoader() + .loadClass(instrumenter.getClass().getName() + "$TracerClassInstrumentation") + .getDeclaredConstructor() + .newInstance(); + } + try { + // Ratpack injects the scope manager as a helper. + // This is likely a bug, but we'll grandfather it out of the helper checks for now. + if (!instrumenter.getClass().getName().contains("Ratpack")) { + // verify helper injector works + final String[] helperClassNames = instrumenter.helperClassNames(); + if (helperClassNames.length > 0) { + new HelperInjector(helperClassNames).transform(null, null, cl, null); + } + } + } catch (Exception e) { + System.err.println( + "FAILED HELPER INJECTION. Are Helpers being injected in the correct order?"); + throw e; + } + } + } + + private MuzzleVersionScanPlugin() {} +} diff --git a/dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/muzzle/MuzzleVisitor.java b/dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/muzzle/MuzzleVisitor.java index 81057d164b..9fb91d0d51 100644 --- a/dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/muzzle/MuzzleVisitor.java +++ b/dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/muzzle/MuzzleVisitor.java @@ -1,6 +1,7 @@ package datadog.trace.agent.tooling.muzzle; -import java.util.Collection; +import datadog.trace.agent.tooling.Instrumenter; +import datadog.trace.agent.tooling.Utils; import java.util.HashMap; import java.util.HashSet; import java.util.Map; @@ -14,10 +15,7 @@ import net.bytebuddy.implementation.Implementation; import net.bytebuddy.jar.asm.*; import net.bytebuddy.pool.TypePool; -/** - * Visit a class and add: 1) a private instrumenationMuzzle field and getter AND 2) logic to the end - * of the instrumentation transformer to assert classpath is safe to apply instrumentation to. - */ +/** Visit a class and add: a private instrumenationMuzzle field and getter */ public class MuzzleVisitor implements AsmVisitorWrapper { @Override public int mergeWriter(int flags) { @@ -44,7 +42,7 @@ public class MuzzleVisitor implements AsmVisitorWrapper { public static class InsertSafetyMatcher extends ClassVisitor { private String instrumentationClassName; - private Set adviceClassNames = new HashSet<>(); + private Instrumenter.Default instrumenter; public InsertSafetyMatcher(ClassVisitor classVisitor) { super(Opcodes.ASM6, classVisitor); @@ -59,6 +57,17 @@ public class MuzzleVisitor implements AsmVisitorWrapper { final String superName, final String[] interfaces) { this.instrumentationClassName = name; + try { + instrumenter = + (Instrumenter.Default) + MuzzleVisitor.class + .getClassLoader() + .loadClass(Utils.getClassName(instrumentationClassName)) + .getDeclaredConstructor() + .newInstance(); + } catch (Exception e) { + throw new RuntimeException(e); + } super.visit(version, access, name, signature, superName, interfaces); } @@ -74,19 +83,24 @@ public class MuzzleVisitor implements AsmVisitorWrapper { if ("".equals(name)) { methodVisitor = new InitializeFieldVisitor(methodVisitor); } - return new InsertMuzzleTransformer(methodVisitor); + return methodVisitor; } public Reference[] generateReferences() { // track sources we've generated references from to avoid recursion final Set referenceSources = new HashSet<>(); final Map references = new HashMap<>(); + final Set adviceClassNames = new HashSet<>(); + + for (String adviceClassName : instrumenter.transformers().values()) { + adviceClassNames.add(adviceClassName); + } for (String adviceClass : adviceClassNames) { if (!referenceSources.contains(adviceClass)) { referenceSources.add(adviceClass); for (Map.Entry entry : - AdviceReferenceVisitor.createReferencesFrom( + ReferenceCreator.createReferencesFrom( adviceClass, ReferenceMatcher.class.getClassLoader()) .entrySet()) { if (references.containsKey(entry.getKey())) { @@ -105,10 +119,11 @@ public class MuzzleVisitor implements AsmVisitorWrapper { public void visitEnd() { { // generate getInstrumentationMuzzle method /* - * private synchronized ReferenceMatcher getInstrumentationMuzzle() { + * protected synchronized ReferenceMatcher getInstrumentationMuzzle() { * if (null == this.instrumentationMuzzle) { - * this.instrumentationMuzzle = new ReferenceMatcher(new Reference[]{ - * //reference builders + * this.instrumentationMuzzle = new ReferenceMatcher(this.helperClassNames(), + * new Reference[]{ + * //reference builders * }); * } * return this.instrumentationMuzzle; @@ -116,7 +131,7 @@ public class MuzzleVisitor implements AsmVisitorWrapper { */ final MethodVisitor mv = visitMethod( - Opcodes.ACC_PRIVATE + Opcodes.ACC_SYNCHRONIZED, + Opcodes.ACC_PROTECTED + Opcodes.ACC_SYNCHRONIZED, "getInstrumentationMuzzle", "()Ldatadog/trace/agent/tooling/muzzle/ReferenceMatcher;", null, @@ -137,16 +152,26 @@ public class MuzzleVisitor implements AsmVisitorWrapper { "Ldatadog/trace/agent/tooling/muzzle/ReferenceMatcher;"); mv.visitJumpInsn(Opcodes.IF_ACMPNE, ret); - final Reference[] references = generateReferences(); mv.visitVarInsn(Opcodes.ALOAD, 0); + mv.visitTypeInsn(Opcodes.NEW, "datadog/trace/agent/tooling/muzzle/ReferenceMatcher"); mv.visitInsn(Opcodes.DUP); - mv.visitIntInsn(Opcodes.BIPUSH, references.length); + + mv.visitVarInsn(Opcodes.ALOAD, 0); + mv.visitMethodInsn( + Opcodes.INVOKEVIRTUAL, + instrumentationClassName, + "helperClassNames", + "()[Ljava/lang/String;", + false); + + final Reference[] references = generateReferences(); + mv.visitLdcInsn(references.length); mv.visitTypeInsn(Opcodes.ANEWARRAY, "datadog/trace/agent/tooling/muzzle/Reference"); for (int i = 0; i < references.length; ++i) { mv.visitInsn(Opcodes.DUP); - mv.visitIntInsn(Opcodes.BIPUSH, i); + mv.visitLdcInsn(i); mv.visitTypeInsn(Opcodes.NEW, "datadog/trace/agent/tooling/muzzle/Reference$Builder"); mv.visitInsn(Opcodes.DUP); mv.visitLdcInsn(references[i].getClassName()); @@ -158,7 +183,7 @@ public class MuzzleVisitor implements AsmVisitorWrapper { false); for (Reference.Source source : references[i].getSources()) { mv.visitLdcInsn(source.getName()); - mv.visitIntInsn(Opcodes.BIPUSH, source.getLine()); + mv.visitLdcInsn(source.getLine()); mv.visitMethodInsn( Opcodes.INVOKEVIRTUAL, "datadog/trace/agent/tooling/muzzle/Reference$Builder", @@ -199,14 +224,14 @@ public class MuzzleVisitor implements AsmVisitorWrapper { } for (Reference.Field field : references[i].getFields()) { mv.visitLdcInsn(field.getName()); - mv.visitIntInsn(Opcodes.BIPUSH, field.getFlags().size()); + mv.visitLdcInsn(field.getFlags().size()); mv.visitTypeInsn( Opcodes.ANEWARRAY, "datadog/trace/agent/tooling/muzzle/Reference$Flag"); int j = 0; for (Reference.Flag flag : field.getFlags()) { mv.visitInsn(Opcodes.DUP); - mv.visitIntInsn(Opcodes.BIPUSH, j); + mv.visitLdcInsn(j); mv.visitFieldInsn( Opcodes.GETSTATIC, "datadog/trace/agent/tooling/muzzle/Reference$Flag", @@ -226,13 +251,13 @@ public class MuzzleVisitor implements AsmVisitorWrapper { for (Reference.Method method : references[i].getMethods()) { mv.visitLdcInsn(method.getName()); - mv.visitIntInsn(Opcodes.BIPUSH, method.getFlags().size()); + mv.visitLdcInsn(method.getFlags().size()); mv.visitTypeInsn( Opcodes.ANEWARRAY, "datadog/trace/agent/tooling/muzzle/Reference$Flag"); int j = 0; for (Reference.Flag flag : method.getFlags()) { mv.visitInsn(Opcodes.DUP); - mv.visitIntInsn(Opcodes.BIPUSH, j); + mv.visitLdcInsn(j); mv.visitFieldInsn( Opcodes.GETSTATIC, "datadog/trace/agent/tooling/muzzle/Reference$Flag", @@ -244,13 +269,13 @@ public class MuzzleVisitor implements AsmVisitorWrapper { mv.visitLdcInsn(method.getReturnType()); - mv.visitIntInsn(Opcodes.BIPUSH, method.getParameterTypes().size()); + mv.visitLdcInsn(method.getParameterTypes().size()); mv.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/String"); int k = 0; for (String parameterType : method.getParameterTypes()) { mv.visitInsn(Opcodes.DUP); - mv.visitIntInsn(Opcodes.BIPUSH, k); + mv.visitLdcInsn(k); mv.visitLdcInsn(parameterType); mv.visitInsn(Opcodes.AASTORE); } @@ -275,7 +300,7 @@ public class MuzzleVisitor implements AsmVisitorWrapper { Opcodes.INVOKESPECIAL, "datadog/trace/agent/tooling/muzzle/ReferenceMatcher", "", - "([Ldatadog/trace/agent/tooling/muzzle/Reference;)V", + "([Ljava/lang/String;[Ldatadog/trace/agent/tooling/muzzle/Reference;)V", false); mv.visitFieldInsn( Opcodes.PUTFIELD, @@ -308,106 +333,6 @@ public class MuzzleVisitor implements AsmVisitorWrapper { super.visitEnd(); } - /** - * Changes this:
- *  .transform(DDAdvice.create().advice(named("fooMethod", FooAdvice.class.getname()))) - *  .asDecorator(); Into this:
- *  .transform(DDAdvice.create().advice(named("fooMethod", FooAdvice.class.getname()))) - *  .transform(this.instrumentationMuzzle.assertSafeTransformation("foo.package.FooAdvice")); - *  .asDecorator(); className) - */ - public class InsertMuzzleTransformer extends MethodVisitor { - // it would be nice to manage the state with an enum, but that requires this class to be non-static - private final int INIT = 0; - // SomeClass - private final int PREVIOUS_INSTRUCTION_LDC = 1; - // SomeClass.getName() - private final int PREVIOUS_INSTRUCTION_GET_CLASS_NAME = 2; - - private String lastClassLDC = null; - - private Collection adviceClassNames = new HashSet<>(); - private int STATE = INIT; - - public InsertMuzzleTransformer(MethodVisitor methodVisitor) { - super(Opcodes.ASM6, methodVisitor); - } - - public void reset() { - STATE = INIT; - lastClassLDC = null; - adviceClassNames.clear(); - } - - @Override - public void visitMethodInsn( - final int opcode, - final String owner, - final String name, - final String descriptor, - final boolean isInterface) { - if (name.equals("getName")) { - if (STATE == PREVIOUS_INSTRUCTION_LDC) { - STATE = PREVIOUS_INSTRUCTION_GET_CLASS_NAME; - } - } else if (name.equals("advice")) { - if (STATE == PREVIOUS_INSTRUCTION_GET_CLASS_NAME) { - adviceClassNames.add(lastClassLDC); - InsertSafetyMatcher.this.adviceClassNames.add(lastClassLDC); - } - // add last LDC/ToString to adivce list - } else if (name.equals("asDecorator")) { - this.visitVarInsn(Opcodes.ALOAD, 0); - mv.visitMethodInsn( - Opcodes.INVOKESPECIAL, - instrumentationClassName, - "getInstrumentationMuzzle", - "()Ldatadog/trace/agent/tooling/muzzle/ReferenceMatcher;", - false); - mv.visitIntInsn(Opcodes.BIPUSH, adviceClassNames.size()); - mv.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/String"); - int i = 0; - for (String adviceClassName : adviceClassNames) { - mv.visitInsn(Opcodes.DUP); - mv.visitIntInsn(Opcodes.BIPUSH, i); - mv.visitLdcInsn(adviceClassName); - mv.visitInsn(Opcodes.AASTORE); - ++i; - } - mv.visitMethodInsn( - Opcodes.INVOKEVIRTUAL, - "datadog/trace/agent/tooling/muzzle/ReferenceMatcher", - "assertSafeTransformation", - "([Ljava/lang/String;)Lnet/bytebuddy/agent/builder/AgentBuilder$Transformer;", - false); - mv.visitMethodInsn( - Opcodes.INVOKEINTERFACE, - "net/bytebuddy/agent/builder/AgentBuilder$Identified$Narrowable", - "transform", - "(Lnet/bytebuddy/agent/builder/AgentBuilder$Transformer;)Lnet/bytebuddy/agent/builder/AgentBuilder$Identified$Extendable;", - true); - reset(); - } else { - STATE = INIT; - lastClassLDC = null; - } - super.visitMethodInsn(opcode, owner, name, descriptor, isInterface); - } - - @Override - public void visitLdcInsn(final Object value) { - if (value instanceof Type) { - Type type = (Type) value; - if (type.getSort() == Type.OBJECT) { - lastClassLDC = type.getClassName(); - STATE = PREVIOUS_INSTRUCTION_LDC; - type.getClassName(); - } - } - super.visitLdcInsn(value); - } - } - /** Append a field initializer to the end of a method. */ public class InitializeFieldVisitor extends MethodVisitor { public InitializeFieldVisitor(MethodVisitor methodVisitor) { diff --git a/dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/muzzle/Reference.java b/dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/muzzle/Reference.java index d44bf46247..f8a2184a8f 100644 --- a/dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/muzzle/Reference.java +++ b/dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/muzzle/Reference.java @@ -5,7 +5,7 @@ import static datadog.trace.agent.tooling.ClassLoaderMatcher.BOOTSTRAP_CLASSLOAD import datadog.trace.agent.tooling.Utils; import java.util.*; -/** An immutable reference to a single class file. */ +/** An immutable reference to a jvm class. */ public class Reference { private final Set sources; private final String className; diff --git a/dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/muzzle/AdviceReferenceVisitor.java b/dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/muzzle/ReferenceCreator.java similarity index 92% rename from dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/muzzle/AdviceReferenceVisitor.java rename to dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/muzzle/ReferenceCreator.java index c018a98c4b..12ce1fe4f7 100644 --- a/dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/muzzle/AdviceReferenceVisitor.java +++ b/dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/muzzle/ReferenceCreator.java @@ -7,11 +7,63 @@ import java.util.*; import net.bytebuddy.jar.asm.*; /** Visit a class and collect all references made by the visited class. */ -public class AdviceReferenceVisitor extends ClassVisitor { +public class ReferenceCreator extends ClassVisitor { + /** + * Generate all references reachable from a given class. + * + * @param entryPointClassName Starting point for generating references. + * @param loader Classloader used to read class bytes. + * @return Map of [referenceClassName -> Reference] + */ + public static Map createReferencesFrom( + String entryPointClassName, ClassLoader loader) { + final Set visitedSources = new HashSet<>(); + final Map references = new HashMap<>(); + + final Queue instrumentationQueue = new ArrayDeque<>(); + instrumentationQueue.add(entryPointClassName); + + while (!instrumentationQueue.isEmpty()) { + final String className = instrumentationQueue.remove(); + visitedSources.add(className); + try { + final InputStream in = loader.getResourceAsStream(Utils.getResourceName(className)); + try { + final ReferenceCreator cv = new ReferenceCreator(null); + final ClassReader reader = new ClassReader(in); + reader.accept(cv, ClassReader.SKIP_FRAMES); + + Map instrumentationReferences = cv.getReferences(); + for (Map.Entry entry : instrumentationReferences.entrySet()) { + // Don't generate references created outside of the datadog instrumentation package. + if (!visitedSources.contains(entry.getKey()) + && entry.getKey().startsWith("datadog.trace.instrumentation.")) { + instrumentationQueue.add(entry.getKey()); + } + if (references.containsKey(entry.getKey())) { + references.put( + entry.getKey(), references.get(entry.getKey()).merge(entry.getValue())); + } else { + references.put(entry.getKey(), entry.getValue()); + } + } + + } finally { + if (in != null) { + in.close(); + } + } + } catch (IOException ioe) { + throw new IllegalStateException(ioe); + } + } + return references; + } + private Map references = new HashMap<>(); private String refSourceClassName; - public AdviceReferenceVisitor(ClassVisitor classVisitor) { + private ReferenceCreator(ClassVisitor classVisitor) { super(Opcodes.ASM6, classVisitor); } @@ -51,7 +103,6 @@ public class AdviceReferenceVisitor extends ClassVisitor { } private class AdviceReferenceMethodVisitor extends MethodVisitor { - private boolean isAdviceMethod = false; private int currentLineNumber = -1; public AdviceReferenceMethodVisitor(MethodVisitor methodVisitor) { @@ -75,56 +126,4 @@ public class AdviceReferenceVisitor extends ClassVisitor { new Reference.Builder(owner).withSource(refSourceClassName, currentLineNumber).build()); } } - - /** - * Generate all references reachable from a given class. - * - * @param entryPointClassName Starting point for generating references. - * @param loader Classloader used to read class bytes. - * @return Map of [referenceClassName -> Reference] - */ - public static Map createReferencesFrom( - String entryPointClassName, ClassLoader loader) { - final Set visitedSources = new HashSet<>(); - final Map references = new HashMap<>(); - - final Queue instrumentationQueue = new ArrayDeque<>(); - instrumentationQueue.add(entryPointClassName); - - while (!instrumentationQueue.isEmpty()) { - final String className = instrumentationQueue.remove(); - visitedSources.add(className); - try { - final InputStream in = loader.getResourceAsStream(Utils.getResourceName(className)); - try { - final AdviceReferenceVisitor cv = new AdviceReferenceVisitor(null); - final ClassReader reader = new ClassReader(in); - reader.accept(cv, ClassReader.SKIP_FRAMES); - - Map instrumentationReferences = cv.getReferences(); - for (Map.Entry entry : instrumentationReferences.entrySet()) { - // TODO: expose config instead of hardcoding datadog instrumentation namespace - if (!visitedSources.contains(entry.getKey()) - && entry.getKey().startsWith("datadog.trace.instrumentation.")) { - instrumentationQueue.add(entry.getKey()); - } - if (references.containsKey(entry.getKey())) { - references.put( - entry.getKey(), references.get(entry.getKey()).merge(entry.getValue())); - } else { - references.put(entry.getKey(), entry.getValue()); - } - } - - } finally { - if (in != null) { - in.close(); - } - } - } catch (IOException ioe) { - throw new IllegalStateException(ioe); - } - } - return references; - } } diff --git a/dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/muzzle/ReferenceMatcher.java b/dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/muzzle/ReferenceMatcher.java index cc89db7b0c..cfcbdf4895 100644 --- a/dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/muzzle/ReferenceMatcher.java +++ b/dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/muzzle/ReferenceMatcher.java @@ -3,37 +3,24 @@ package datadog.trace.agent.tooling.muzzle; import static net.bytebuddy.dynamic.loading.ClassLoadingStrategy.BOOTSTRAP_LOADER; import datadog.trace.agent.tooling.Utils; -import java.security.ProtectionDomain; import java.util.*; import lombok.extern.slf4j.Slf4j; -import net.bytebuddy.agent.builder.AgentBuilder; -import net.bytebuddy.agent.builder.AgentBuilder.Transformer; -import net.bytebuddy.description.type.TypeDescription; -import net.bytebuddy.dynamic.DynamicType; -import net.bytebuddy.utility.JavaModule; -/** - * A bytebuddy matcher that matches if expected references (classes, fields, methods, visibility) - * are present on the classpath. - */ +/** Matches a set of references against a classloader. */ @Slf4j -public class ReferenceMatcher implements AgentBuilder.RawMatcher { +public class ReferenceMatcher { private final Map> mismatchCache = Collections.synchronizedMap(new WeakHashMap>()); private final Reference[] references; + private final Set helperClassNames; public ReferenceMatcher(Reference... references) { - this.references = references; + this(new String[0], references); } - @Override - public boolean matches( - TypeDescription typeDescription, - ClassLoader classLoader, - JavaModule module, - Class classBeingRedefined, - ProtectionDomain protectionDomain) { - return matches(classLoader); + public ReferenceMatcher(String[] helperClassNames, Reference[] references) { + this.references = references; + this.helperClassNames = new HashSet<>(Arrays.asList(helperClassNames)); } /** @@ -52,54 +39,23 @@ public class ReferenceMatcher implements AgentBuilder.RawMatcher { if (loader == BOOTSTRAP_LOADER) { loader = Utils.getBootstrapProxy(); } - final List mismatchedReferences = new ArrayList<>(0); - for (Reference reference : references) { - mismatchedReferences.addAll(reference.checkMatch(loader)); - } - return mismatchedReferences; - } - - /** - * Create a bytebuddy matcher which throws a MismatchException when there are mismatches with the - * classloader under transformation. - */ - public Transformer assertSafeTransformation(String... adviceClassNames) { - return new Transformer() { - @Override - public DynamicType.Builder transform( - DynamicType.Builder builder, - TypeDescription typeDescription, - ClassLoader classLoader, - JavaModule module) { - if (classLoader == BOOTSTRAP_LOADER) { - classLoader = Utils.getBootstrapProxy(); - } - List mismatches = - mismatchCache.get(getMismatchedReferenceSources(classLoader)); + List mismatches = mismatchCache.get(loader); + if (null == mismatches) { + synchronized (loader) { + mismatches = mismatchCache.get(loader); if (null == mismatches) { - // okay if entered by multiple callers during initialization - mismatches = getMismatchedReferenceSources(classLoader); - mismatchCache.put(classLoader, mismatches); - } - if (mismatches.size() == 0) { - return builder; - } else { - throw new MismatchException(classLoader, mismatches); + mismatches = new ArrayList<>(0); + for (Reference reference : references) { + // Don't reference-check helper classes. + // They will be injected by the instrumentation's HelperInjector. + if (!helperClassNames.contains(reference.getClassName())) { + mismatches.addAll(reference.checkMatch(loader)); + } + } + mismatchCache.put(loader, mismatches); } } - }; - } - - public static class MismatchException extends RuntimeException { - private final List mismatches; - - public MismatchException(ClassLoader classLoader, List mismatches) { - super(mismatches.size() + " mismatches on classloader: " + classLoader); - this.mismatches = mismatches; - } - - public List getMismatches() { - return this.mismatches; } + return mismatches; } } diff --git a/dd-java-agent/instrumentation/akka-http-10.0/src/lagomTest/java/EchoService.java b/dd-java-agent/instrumentation/akka-http-10.0/src/lagomTest/java/EchoService.java index 747804b3d5..74db83c669 100644 --- a/dd-java-agent/instrumentation/akka-http-10.0/src/lagomTest/java/EchoService.java +++ b/dd-java-agent/instrumentation/akka-http-10.0/src/lagomTest/java/EchoService.java @@ -10,6 +10,7 @@ public interface EchoService extends Service { ServiceCall, Source> error(); + @Override default Descriptor descriptor() { return named("echo").withCalls(namedCall("echo", this::echo), namedCall("error", this::error)); } diff --git a/dd-java-agent/instrumentation/elasticsearch-rest-5/src/main/java/datadog/trace/instrumentation/elasticsearch5/Elasticsearch5RestClientInstrumentation.java b/dd-java-agent/instrumentation/elasticsearch-rest-5/src/main/java/datadog/trace/instrumentation/elasticsearch5/Elasticsearch5RestClientInstrumentation.java index 49e485b338..256c04e90e 100644 --- a/dd-java-agent/instrumentation/elasticsearch-rest-5/src/main/java/datadog/trace/instrumentation/elasticsearch5/Elasticsearch5RestClientInstrumentation.java +++ b/dd-java-agent/instrumentation/elasticsearch-rest-5/src/main/java/datadog/trace/instrumentation/elasticsearch5/Elasticsearch5RestClientInstrumentation.java @@ -35,6 +35,11 @@ public class Elasticsearch5RestClientInstrumentation extends Instrumenter.Defaul return false; } + @Override + public String[] helperClassNames() { + return new String[] {"datadog.trace.instrumentation.elasticsearch5.RestResponseListener"}; + } + @Override public ElementMatcher typeMatcher() { return not(isInterface()).and(named("org.elasticsearch.client.RestClient")); diff --git a/dd-java-agent/instrumentation/instrumentation.gradle b/dd-java-agent/instrumentation/instrumentation.gradle index 96d379b9de..2106cc51bd 100644 --- a/dd-java-agent/instrumentation/instrumentation.gradle +++ b/dd-java-agent/instrumentation/instrumentation.gradle @@ -14,6 +14,7 @@ Project instr_project = project subprojects { subProj -> if (subProj.getParent() == instr_project) { apply plugin: "net.bytebuddy.byte-buddy" + apply plugin: 'muzzle' subProj.byteBuddy { transformation { diff --git a/dd-java-agent/instrumentation/mongo-async-3.3/mongo-async-3.3.gradle b/dd-java-agent/instrumentation/mongo-async-3.3/mongo-async-3.3.gradle index 1fc6ce75d4..3970abbb98 100644 --- a/dd-java-agent/instrumentation/mongo-async-3.3/mongo-async-3.3.gradle +++ b/dd-java-agent/instrumentation/mongo-async-3.3/mongo-async-3.3.gradle @@ -17,6 +17,7 @@ dependencies { compile(project(':dd-java-agent:instrumentation:mongo-3.1')) { transitive = false } + compileOnly group: 'org.mongodb', name: 'mongo-java-driver', version: '3.4.2' compileOnly group: 'org.mongodb', name: 'mongodb-driver-async', version: '3.4.2' compile project(':dd-java-agent:agent-tooling') diff --git a/dd-java-agent/instrumentation/ratpack-1.4/src/main/java/datadog/trace/instrumentation/ratpack/RatpackInstrumentation.java b/dd-java-agent/instrumentation/ratpack-1.4/src/main/java/datadog/trace/instrumentation/ratpack/RatpackInstrumentation.java index 1502300456..a536a86c45 100644 --- a/dd-java-agent/instrumentation/ratpack-1.4/src/main/java/datadog/trace/instrumentation/ratpack/RatpackInstrumentation.java +++ b/dd-java-agent/instrumentation/ratpack-1.4/src/main/java/datadog/trace/instrumentation/ratpack/RatpackInstrumentation.java @@ -54,6 +54,8 @@ public final class RatpackInstrumentation extends Instrumenter.Default { // service registry helpers "datadog.trace.instrumentation.ratpack.impl.RatpackRequestExtractAdapter", "datadog.trace.instrumentation.ratpack.impl.RatpackScopeManager", + "datadog.trace.instrumentation.ratpack.impl.RatpackScopeManager$RatpackScope", + "datadog.trace.instrumentation.ratpack.impl.RatpackServerAdvice", "datadog.trace.instrumentation.ratpack.impl.RatpackServerAdvice$RatpackServerRegistryAdvice", "datadog.trace.instrumentation.ratpack.impl.TracingHandler" }; diff --git a/dd-java-agent/instrumentation/spymemcached-2.12/src/main/java/datadog/trace/instrumentation/spymemcached/MemcachedClientInstrumentation.java b/dd-java-agent/instrumentation/spymemcached-2.12/src/main/java/datadog/trace/instrumentation/spymemcached/MemcachedClientInstrumentation.java index c3cc01de82..eb6923144f 100644 --- a/dd-java-agent/instrumentation/spymemcached-2.12/src/main/java/datadog/trace/instrumentation/spymemcached/MemcachedClientInstrumentation.java +++ b/dd-java-agent/instrumentation/spymemcached-2.12/src/main/java/datadog/trace/instrumentation/spymemcached/MemcachedClientInstrumentation.java @@ -49,6 +49,7 @@ public final class MemcachedClientInstrumentation extends Instrumenter.Default { public String[] helperClassNames() { return new String[] { HELPERS_PACKAGE + ".CompletionListener", + HELPERS_PACKAGE + ".SyncCompletionListener", HELPERS_PACKAGE + ".GetCompletionListener", HELPERS_PACKAGE + ".OperationCompletionListener", HELPERS_PACKAGE + ".BulkGetCompletionListener" diff --git a/dd-java-agent/instrumentation/trace-annotation/src/main/java/datadog/trace/instrumentation/trace_annotation/TraceConfigInstrumentation.java b/dd-java-agent/instrumentation/trace-annotation/src/main/java/datadog/trace/instrumentation/trace_annotation/TraceConfigInstrumentation.java index 502eef6bdd..79744ec1c4 100644 --- a/dd-java-agent/instrumentation/trace-annotation/src/main/java/datadog/trace/instrumentation/trace_annotation/TraceConfigInstrumentation.java +++ b/dd-java-agent/instrumentation/trace-annotation/src/main/java/datadog/trace/instrumentation/trace_annotation/TraceConfigInstrumentation.java @@ -17,9 +17,18 @@ import net.bytebuddy.description.method.MethodDescription; import net.bytebuddy.description.type.TypeDescription; import net.bytebuddy.matcher.ElementMatcher; +/** + * TraceConfig Instrumentation does not extend Default. + * + *

Instead it directly implements Instrumenter#instrument() and adds one default Instrumenter for + * every configured class+method-list. + * + *

If this becomes a more common use case the building logic should be abstracted out into a + * super class. + */ @Slf4j @AutoService(Instrumenter.class) -public class TraceConfigInstrumentation extends Instrumenter.Default { +public class TraceConfigInstrumentation implements Instrumenter { private static final String CONFIG_NAME = "dd.trace.methods"; static final String PACKAGE_CLASS_NAME_REGEX = "[\\w.\\$]+"; @@ -38,9 +47,7 @@ public class TraceConfigInstrumentation extends Instrumenter.Default { private final Map> classMethodsToTrace; public TraceConfigInstrumentation() { - super("trace", "trace-config"); - - final String configString = getPropOrEnv(CONFIG_NAME); + final String configString = Default.getPropOrEnv(CONFIG_NAME); if (configString == null || configString.trim().isEmpty()) { classMethodsToTrace = Collections.emptyMap(); @@ -97,6 +104,11 @@ public class TraceConfigInstrumentation extends Instrumenter.Default { private final String className; private final Set methodNames; + /** No-arg constructor only used by muzzle and tests. */ + public TracerClassInstrumentation() { + this("noop", Collections.singleton("noop")); + } + public TracerClassInstrumentation(String className, Set methodNames) { super("trace", "trace-config"); this.className = className; @@ -130,6 +142,16 @@ public class TraceConfigInstrumentation extends Instrumenter.Default { throw new RuntimeException("TracerConfigInstrumentation must not use TypeMatcher"); } + @Override + public ElementMatcher classLoaderMatcher() { + throw new RuntimeException("TracerConfigInstrumentation must not use classLoaderMatcher"); + } + + @Override + public String[] helperClassNames() { + throw new RuntimeException("TracerConfigInstrumentation must not use helperClassNames"); + } + @Override public Map transformers() { throw new RuntimeException("TracerConfigInstrumentation must not use transformers."); diff --git a/dd-java-agent/testing/src/test/groovy/muzzle/AdviceReferenceVisitorTest.groovy b/dd-java-agent/testing/src/test/groovy/muzzle/AdviceReferenceVisitorTest.groovy index 097b37f8af..e05ca43c07 100644 --- a/dd-java-agent/testing/src/test/groovy/muzzle/AdviceReferenceVisitorTest.groovy +++ b/dd-java-agent/testing/src/test/groovy/muzzle/AdviceReferenceVisitorTest.groovy @@ -2,7 +2,7 @@ package muzzle import datadog.trace.agent.test.AgentTestRunner import datadog.trace.agent.test.TestUtils -import datadog.trace.agent.tooling.muzzle.AdviceReferenceVisitor +import datadog.trace.agent.tooling.muzzle.ReferenceCreator import datadog.trace.agent.tooling.muzzle.ReferenceMatcher import datadog.trace.agent.tooling.muzzle.Reference @@ -10,7 +10,7 @@ class AdviceReferenceVisitorTest extends AgentTestRunner { def "methods body references"() { setup: - Map references = AdviceReferenceVisitor.createReferencesFrom(AdviceClass.getName(), this.getClass().getClassLoader()) + Map references = ReferenceCreator.createReferencesFrom(AdviceClass.getName(), this.getClass().getClassLoader()) expect: references.get('java.lang.Object') != null @@ -22,9 +22,8 @@ class AdviceReferenceVisitorTest extends AgentTestRunner { def "match safe classpaths"() { setup: - Reference[] refs = AdviceReferenceVisitor.createReferencesFrom(AdviceClass.getName(), this.getClass().getClassLoader()).values().toArray(new Reference[0]) + Reference[] refs = ReferenceCreator.createReferencesFrom(AdviceClass.getName(), this.getClass().getClassLoader()).values().toArray(new Reference[0]) ReferenceMatcher refMatcher = new ReferenceMatcher(refs) - refMatcher.assertSafeTransformation() ClassLoader safeClassloader = new URLClassLoader([TestUtils.createJarWithClasses(AdviceClass$A, AdviceClass$SomeInterface, AdviceClass$SomeImplementation)] as URL[], diff --git a/settings.gradle b/settings.gradle index eab8e57289..c4f843e258 100644 --- a/settings.gradle +++ b/settings.gradle @@ -13,7 +13,6 @@ include ':dd-java-agent:instrumentation:akka-http-10.0' include ':dd-java-agent:instrumentation:apache-httpclient-4.3' 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:elasticsearch-rest-5' include ':dd-java-agent:instrumentation:elasticsearch-transport-2'