-
Notifications
You must be signed in to change notification settings - Fork 292
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #383 from DataDog/ark/muzzle-hookup
Enable Muzzle validation for Default Instrumentation Match phase
- Loading branch information
Showing
22 changed files
with
383 additions
and
302 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
class MuzzleExtension { | ||
String group | ||
String module | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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. | ||
* | ||
* <p/>TODO: merge this with version scan | ||
*/ | ||
class MuzzlePlugin implements Plugin<Project> { | ||
@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<URL> 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<URL> 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) | ||
} | ||
} | ||
} |
1 change: 1 addition & 0 deletions
1
buildSrc/src/main/resources/META-INF/gradle-plugins/muzzle.properties
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
implementation-class=MuzzlePlugin |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
86 changes: 86 additions & 0 deletions
86
...ent-tooling/src/main/java/datadog/trace/agent/tooling/muzzle/MuzzleVersionScanPlugin.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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. | ||
* | ||
* <p>For each instrumenter on the classpath, run muzzle validation and throw an exception if any | ||
* mismatches are detected. | ||
* | ||
* <p>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<Reference.Mismatch> 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() {} | ||
} |
Oops, something went wrong.