Getting the -javaagent parameter is necessary in some cases
This commit is contained in:
parent
1a26e73ae8
commit
ff0cd73381
|
@ -121,7 +121,6 @@ dependencies {
|
|||
tasks.withType(Test).configureEach {
|
||||
jvmArgs "-Ddd.service.name=java-agent-tests"
|
||||
jvmArgs "-Ddd.writer.type=LoggingWriter"
|
||||
jvmArgs "-Dagent.jar.to.forward=${shadowJar.archivePath}"
|
||||
// Multi-threaded logging seems to be causing deadlocks with Gradle's log capture.
|
||||
// jvmArgs "-Ddatadog.slf4j.simpleLogger.defaultLogLevel=debug"
|
||||
// jvmArgs "-Dorg.slf4j.simpleLogger.defaultLogLevel=debug"
|
||||
|
|
|
@ -5,14 +5,20 @@ import java.io.File;
|
|||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.lang.instrument.Instrumentation;
|
||||
import java.lang.management.ManagementFactory;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.net.URISyntaxException;
|
||||
import java.net.URL;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.security.CodeSource;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.jar.JarFile;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/** Entry point for initializing the agent. */
|
||||
public class TracingAgent {
|
||||
|
@ -151,16 +157,103 @@ public class TracingAgent {
|
|||
|
||||
private static synchronized URL installBootstrapJar(
|
||||
final Instrumentation inst, final boolean usingCustomLogManager)
|
||||
throws IOException, URISyntaxException, ClassNotFoundException {
|
||||
throws IOException, URISyntaxException {
|
||||
URL bootstrapURL = null;
|
||||
|
||||
// First try Code Source
|
||||
final CodeSource codeSource = TracingAgent.class.getProtectionDomain().getCodeSource();
|
||||
|
||||
if (codeSource != null) {
|
||||
final URL bootstrapURL = codeSource.getLocation();
|
||||
bootstrapURL = codeSource.getLocation();
|
||||
final File bootstrapFile = new File(bootstrapURL.toURI());
|
||||
|
||||
inst.appendToBootstrapClassLoaderSearch(new JarFile(new File(bootstrapURL.toURI())));
|
||||
return bootstrapURL;
|
||||
if (!bootstrapFile.isDirectory()) {
|
||||
inst.appendToBootstrapClassLoaderSearch(new JarFile(bootstrapFile));
|
||||
return bootstrapURL;
|
||||
}
|
||||
}
|
||||
|
||||
System.out.println("Could not get bootstrap jar from code source, using -javaagent arg");
|
||||
|
||||
// ManagementFactory indirectly references java.util.logging.LogManager
|
||||
// - On Oracle-based JDKs after 1.8
|
||||
// - On IBM-based JDKs since at least 1.7
|
||||
// This prevents custom log managers from working correctly
|
||||
// Use reflection to bypass the loading of the class
|
||||
final List<String> arguments;
|
||||
if (usingCustomLogManager) {
|
||||
System.out.println("Custom log manager detected: getting vm args through reflection");
|
||||
arguments = getVMArgumentsThroughReflection();
|
||||
} else {
|
||||
throw new RuntimeException("Unable to install bootstrap jar. Code source not found");
|
||||
arguments = ManagementFactory.getRuntimeMXBean().getInputArguments();
|
||||
}
|
||||
|
||||
String agentArgument = null;
|
||||
for (final String arg : arguments) {
|
||||
if (arg.startsWith("-javaagent")) {
|
||||
if (agentArgument == null) {
|
||||
agentArgument = arg;
|
||||
} else {
|
||||
throw new RuntimeException(
|
||||
"Multiple javaagents specified and code source unavailable, not installing tracing agent");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (agentArgument == null) {
|
||||
throw new RuntimeException(
|
||||
"Could not find javaagent parameter and code source unavailable, not installing tracing agent");
|
||||
}
|
||||
|
||||
// argument is of the form -javaagent:/path/to/dd-java-agent.jar=optionalargumentstring
|
||||
final Matcher matcher = Pattern.compile("-javaagent:([^=]+).*").matcher(agentArgument);
|
||||
|
||||
if (!matcher.matches()) {
|
||||
throw new RuntimeException("Unable to parse javaagent parameter: " + agentArgument);
|
||||
}
|
||||
|
||||
bootstrapURL = new URL("file:" + matcher.group(1));
|
||||
inst.appendToBootstrapClassLoaderSearch(new JarFile(new File(bootstrapURL.toURI())));
|
||||
|
||||
return bootstrapURL;
|
||||
}
|
||||
|
||||
private static List<String> getVMArgumentsThroughReflection() {
|
||||
try {
|
||||
// Try Oracle-based
|
||||
final Class managementFactoryHelperClass =
|
||||
TracingAgent.class.getClassLoader().loadClass("sun.management.ManagementFactoryHelper");
|
||||
|
||||
final Class vmManagementClass =
|
||||
TracingAgent.class.getClassLoader().loadClass("sun.management.VMManagement");
|
||||
|
||||
Object vmManagement;
|
||||
|
||||
try {
|
||||
vmManagement =
|
||||
managementFactoryHelperClass.getDeclaredMethod("getVMManagement").invoke(null);
|
||||
} catch (final NoSuchMethodException e) {
|
||||
// Older vm before getVMManagement() existed
|
||||
final Field field = managementFactoryHelperClass.getDeclaredField("jvm");
|
||||
field.setAccessible(true);
|
||||
vmManagement = field.get(null);
|
||||
field.setAccessible(false);
|
||||
}
|
||||
|
||||
return (List<String>) vmManagementClass.getMethod("getVmArguments").invoke(vmManagement);
|
||||
|
||||
} catch (final ReflectiveOperationException e) {
|
||||
try { // Try IBM-based.
|
||||
final Class VMClass = TracingAgent.class.getClassLoader().loadClass("com.ibm.oti.vm.VM");
|
||||
final String[] argArray = (String[]) VMClass.getMethod("getVMArgs").invoke(null);
|
||||
return Arrays.asList(argArray);
|
||||
} catch (final ReflectiveOperationException e1) {
|
||||
// Fallback to default
|
||||
System.out.println(
|
||||
"WARNING: Unable to get VM args through reflection. A custom java.util.logging.LogManager may not work correctly");
|
||||
|
||||
return ManagementFactory.getRuntimeMXBean().getInputArguments();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -5,8 +5,7 @@ import jvmbootstraptest.AgentLoadedChecker
|
|||
import spock.lang.Specification
|
||||
|
||||
class AgentLoadedIntoBootstrapTest extends Specification {
|
||||
|
||||
|
||||
|
||||
def "Agent loads in when separate jvm is launched"() {
|
||||
expect:
|
||||
IntegrationTestUtils.runOnSeparateJvm(AgentLoadedChecker.getName()
|
||||
|
|
|
@ -10,6 +10,8 @@ import java.io.FileOutputStream;
|
|||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.lang.management.ManagementFactory;
|
||||
import java.lang.management.RuntimeMXBean;
|
||||
import java.lang.reflect.Field;
|
||||
import java.net.URL;
|
||||
import java.util.ArrayList;
|
||||
|
@ -175,6 +177,17 @@ public class IntegrationTestUtils {
|
|||
return (String[]) f.get(null);
|
||||
}
|
||||
|
||||
private static String getAgentArgument() {
|
||||
final RuntimeMXBean runtimeMxBean = ManagementFactory.getRuntimeMXBean();
|
||||
for (final String arg : runtimeMxBean.getInputArguments()) {
|
||||
if (arg.startsWith("-javaagent")) {
|
||||
return arg;
|
||||
}
|
||||
}
|
||||
|
||||
throw new RuntimeException("Agent jar not found");
|
||||
}
|
||||
|
||||
/**
|
||||
* On a separate JVM, run the main method for a given class.
|
||||
*
|
||||
|
@ -192,18 +205,11 @@ public class IntegrationTestUtils {
|
|||
throws Exception {
|
||||
|
||||
final String separator = System.getProperty("file.separator");
|
||||
final String agentJar = System.getProperty("agent.jar.to.forward");
|
||||
|
||||
if (agentJar == null) {
|
||||
throw new RuntimeException("agent.jar.to.forward property must be set");
|
||||
}
|
||||
|
||||
final String classpath =
|
||||
agentJar + System.getProperty("path.separator") + System.getProperty("java.class.path");
|
||||
final String classpath = System.getProperty("java.class.path");
|
||||
final String path = System.getProperty("java.home") + separator + "bin" + separator + "java";
|
||||
|
||||
final List<String> vmArgsList = new ArrayList<>(Arrays.asList(jvmArgs));
|
||||
vmArgsList.add("-javaagent:" + agentJar);
|
||||
vmArgsList.add(getAgentArgument());
|
||||
|
||||
final List<String> commands = new ArrayList<>();
|
||||
commands.add(path);
|
||||
|
@ -212,7 +218,6 @@ public class IntegrationTestUtils {
|
|||
commands.add(classpath);
|
||||
commands.add(mainClassName);
|
||||
commands.addAll(Arrays.asList(mainMethodArgs));
|
||||
|
||||
final ProcessBuilder processBuilder = new ProcessBuilder(commands.toArray(new String[0]));
|
||||
processBuilder.environment().putAll(envVars);
|
||||
final Process process = processBuilder.start();
|
||||
|
|
Loading…
Reference in New Issue