diff --git a/dd-java-agent/dd-java-agent.gradle b/dd-java-agent/dd-java-agent.gradle index f408630093..554ce7cdc2 100644 --- a/dd-java-agent/dd-java-agent.gradle +++ b/dd-java-agent/dd-java-agent.gradle @@ -13,6 +13,9 @@ description = 'dd-java-agent' apply from: "${rootDir}/gradle/java.gradle" apply from: "${rootDir}/gradle/publish.gradle" +configurations { + shadowInclude +} /* * Include subproject's shadowJar in the dd-java-agent jar. * Note jarname must end in .zip, or its classes will be on the classpath of @@ -56,7 +59,6 @@ def includeShadowJar(subproject, jarname) { } } -includeShadowJar(project(':dd-java-agent:agent-bootstrap'), 'agent-bootstrap.jar.zip') includeShadowJar(project(':dd-java-agent:instrumentation'), 'agent-tooling-and-instrumentation.jar.zip') includeShadowJar(project(':dd-java-agent:agent-jmxfetch'), 'agent-jmxfetch.jar.zip') @@ -75,13 +77,28 @@ jar { } shadowJar { + configurations = [project.configurations.shadowInclude] + classifier null mergeServiceFiles() + exclude '**/module-info.class' + dependencies { exclude(dependency("org.projectlombok:lombok:$versions.lombok")) } + + // Prevents conflict with other SLF4J instances. Important for premain. + relocate 'org.slf4j', 'datadog.slf4j' + // rewrite dependencies calling Logger.getLogger + relocate 'java.util.logging.Logger', 'datadog.trace.bootstrap.PatchLogger' + + if (!project.hasProperty("disableShadowRelocate") || !disableShadowRelocate) { + // shadow OT impl to prevent casts to implementation + relocate 'datadog.trace.common', 'datadog.trace.agent.common' + relocate 'datadog.opentracing', 'datadog.trace.agent.ot' + } } // We don't want bundled dependencies to show up in the pom. @@ -97,6 +114,8 @@ dependencies { testCompile deps.opentracingMock testCompile deps.testLogging testCompile deps.guava + + shadowInclude project(':dd-java-agent:agent-bootstrap') } tasks.withType(Test).configureEach { diff --git a/dd-java-agent/src/main/java/datadog/trace/agent/TracingAgent.java b/dd-java-agent/src/main/java/datadog/trace/agent/TracingAgent.java index 635f9b60cd..0030c5a9ed 100644 --- a/dd-java-agent/src/main/java/datadog/trace/agent/TracingAgent.java +++ b/dd-java-agent/src/main/java/datadog/trace/agent/TracingAgent.java @@ -2,11 +2,8 @@ package datadog.trace.agent; import java.io.BufferedReader; import java.io.File; -import java.io.FileOutputStream; import java.io.IOException; -import java.io.InputStream; import java.io.InputStreamReader; -import java.io.OutputStream; import java.lang.instrument.Instrumentation; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; @@ -30,7 +27,7 @@ public class TracingAgent { // fields must be managed under class lock private static ClassLoader AGENT_CLASSLOADER = null; private static ClassLoader JMXFETCH_CLASSLOADER = null; - private static File bootstrapJar = null; + private static URL BOOTSTRAP_URL = null; public static void premain(final String agentArgs, final Instrumentation inst) throws Exception { agentmain(agentArgs, inst); @@ -39,7 +36,7 @@ public class TracingAgent { public static void agentmain(final String agentArgs, final Instrumentation inst) throws Exception { configureLogger(); - startDatadogAgent(agentArgs, inst); + startDatadogAgent(inst); if (isAppUsingCustomLogManager()) { System.out.println("Custom logger detected. Delaying JMXFetch initialization."); /* @@ -62,25 +59,22 @@ public class TracingAgent { @Override public void run() { try { - startJmxFetch(); + startJmxFetch(inst); } catch (final Exception e) { throw new RuntimeException(e); } } }); } else { - startJmxFetch(); + startJmxFetch(inst); } } - public static synchronized void startDatadogAgent( - final String agentArgs, final Instrumentation inst) throws Exception { - initializeJars(); + public static synchronized void startDatadogAgent(final Instrumentation inst) throws Exception { + installBootstrapJar(inst); if (AGENT_CLASSLOADER == null) { - // bootstrap jar must be appended before agent classloader is created. - inst.appendToBootstrapClassLoaderSearch(new JarFile(bootstrapJar)); final ClassLoader agentClassLoader = - createDatadogClassLoader(bootstrapJar, "agent-tooling-and-instrumentation.jar.zip"); + createDatadogClassLoader("agent-tooling-and-instrumentation.jar.zip"); final ClassLoader contextLoader = Thread.currentThread().getContextClassLoader(); try { Thread.currentThread().setContextClassLoader(agentClassLoader); @@ -107,11 +101,10 @@ public class TracingAgent { } } - public static synchronized void startJmxFetch() throws Exception { - initializeJars(); + public static synchronized void startJmxFetch(final Instrumentation inst) throws Exception { + installBootstrapJar(inst); if (JMXFETCH_CLASSLOADER == null) { - final ClassLoader jmxFetchClassLoader = - createDatadogClassLoader(bootstrapJar, "agent-jmxfetch.jar.zip"); + final ClassLoader jmxFetchClassLoader = createDatadogClassLoader("agent-jmxfetch.jar.zip"); final ClassLoader contextLoader = Thread.currentThread().getContextClassLoader(); try { Thread.currentThread().setContextClassLoader(jmxFetchClassLoader); @@ -138,18 +131,13 @@ public class TracingAgent { } } - /** - * Extract embeded jars out of the dd-java-agent to a temporary location. - * - *

Has no effect if jars are already extracted. - */ - private static synchronized void initializeJars() throws Exception { - if (bootstrapJar == null) { - bootstrapJar = - extractToTmpFile( - TracingAgent.class.getClassLoader(), - "agent-bootstrap.jar.zip", - "agent-bootstrap.jar"); + private static synchronized void installBootstrapJar(final Instrumentation inst) + throws Exception { + if (BOOTSTRAP_URL == null) { + BOOTSTRAP_URL = TracingAgent.class.getProtectionDomain().getCodeSource().getLocation(); + + // bootstrap jar must be appended before agent classloader is created. + inst.appendToBootstrapClassLoaderSearch(new JarFile(new File(BOOTSTRAP_URL.toURI()))); } } @@ -157,13 +145,12 @@ public class TracingAgent { * Create the datadog classloader. This must be called after the bootstrap jar has been appened to * the bootstrap classpath. * - * @param bootstrapJar datadog bootstrap jar which has been appended to the bootstrap loader * @param innerJarFilename Filename of internal jar to use for the classpath of the datadog * classloader * @return Datadog Classloader */ - private static ClassLoader createDatadogClassLoader( - final File bootstrapJar, final String innerJarFilename) throws Exception { + private static ClassLoader createDatadogClassLoader(final String innerJarFilename) + throws Exception { final ClassLoader agentParent; final String javaVersion = System.getProperty("java.version"); if (javaVersion.startsWith("1.7") || javaVersion.startsWith("1.8")) { @@ -180,53 +167,7 @@ public class TracingAgent { URL.class, String.class, ClassLoader.class, ClassLoader.class); return (ClassLoader) constructor.newInstance( - bootstrapJar.toURI().toURL(), - innerJarFilename, - TracingAgent.class.getClassLoader(), - agentParent); - } - - /** Extract sourcePath out of loader to a temporary file named destName. */ - private static File extractToTmpFile( - final ClassLoader loader, final String sourcePath, final String destName) throws Exception { - final String destPrefix; - final String destSuffix; - { - final int i = destName.lastIndexOf('.'); - if (i > 0) { - destPrefix = destName.substring(0, i); - destSuffix = destName.substring(i); - } else { - destPrefix = destName; - destSuffix = ""; - } - } - InputStream inputStream = null; - OutputStream outputStream = null; - try { - inputStream = loader.getResourceAsStream(sourcePath); - if (inputStream == null) { - throw new RuntimeException(sourcePath + ": Not found by loader: " + loader); - } - - int readBytes; - final byte[] buffer = new byte[4096]; - final File tmpFile = File.createTempFile(destPrefix, destSuffix); - tmpFile.deleteOnExit(); - outputStream = new FileOutputStream(tmpFile); - while ((readBytes = inputStream.read(buffer)) > 0) { - outputStream.write(buffer, 0, readBytes); - } - - return tmpFile; - } finally { - if (null != inputStream) { - inputStream.close(); - } - if (null != outputStream) { - outputStream.close(); - } - } + BOOTSTRAP_URL, innerJarFilename, TracingAgent.class.getClassLoader(), agentParent); } private static ClassLoader getPlatformClassLoader()