Skip to content
Merged
Show file tree
Hide file tree
Changes from 11 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions components/cli/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
plugins {
id("me.champeau.jmh")
}

apply(from = "$rootDir/gradle/java.gradle")

jmh {
version = "1.28"
}
102 changes: 102 additions & 0 deletions components/cli/src/main/java/datadog.cli/CLIHelper.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
package datadog.cli;

import de.thetaphi.forbiddenapis.SuppressForbidden;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.lang.management.ManagementFactory;
import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;

public class CLIHelper {
public static final CLIHelper ARGS = new CLIHelper(initJvmArgs());

private final HashSet<String> args;

public CLIHelper(List<String> args) {
this.args = new HashSet<>(args);
}

public HashSet<String> getJvmArgs() {
return this.args;
}

public boolean contains(String argument) {
return this.args.contains(argument);
}

@SuppressForbidden
private static List<String> initJvmArgs() {
// If linux OS, use procfs
// TODO: equals, or contains?
if (System.getProperty("os.name").equalsIgnoreCase("linux")) {
try {
// Get the JVM arguments from /proc/self/cmdline
return getJvmArgsFromProcCmdline();
} catch (IOException e) {
// ignore exception, try other methods
}
}
// Try Oracle-based
// IBM Semeru Runtime 1.8.0_345-b01 will throw UnsatisfiedLinkError here.
try {
final Class<?> managementFactoryHelperClass =
Class.forName("sun.management.ManagementFactoryHelper");

final Class<?> vmManagementClass = Class.forName("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);
}

//noinspection unchecked
return (List<String>) vmManagementClass.getMethod("getVmArguments").invoke(vmManagement);
} catch (final ReflectiveOperationException | UnsatisfiedLinkError ignored) {
// Ignored exception
}

// Try IBM-based.
try {
final Class<?> VMClass = Class.forName("com.ibm.oti.vm.VM");
final String[] argArray = (String[]) VMClass.getMethod("getVMArgs").invoke(null);
return Arrays.asList(argArray);
} catch (final ReflectiveOperationException ignored) {
// Ignored exception
}

// Fallback to default
try {
System.err.println(
"WARNING: Unable to get VM args through reflection. A custom java.util.logging.LogManager may not work correctly");
return ManagementFactory.getRuntimeMXBean().getInputArguments();
} catch (final Throwable t) {
// Throws InvocationTargetException on modularized applications
// with non-opened java.management module
System.err.println("WARNING: Unable to get VM args using managed beans");
}
return Collections.emptyList();
}

private static List<String> getJvmArgsFromProcCmdline() throws IOException {
BufferedReader argsReader = new BufferedReader(new FileReader("/proc/self/cmdline"));
String cmdLine = argsReader.readLine();
if (cmdLine != null) {
// Return JVM arguments as a list of strings split by null characters
return Arrays.asList(cmdLine.split("\0"));
} else {
return null;
}
}
}
1 change: 1 addition & 0 deletions dd-java-agent/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,7 @@ tasks.withType(GenerateMavenPom).configureEach { task ->

dependencies {
implementation project(path: ':components:json')
implementation project(path: ':components:cli')
modules {
module("com.squareup.okio:okio") {
replacedBy("com.datadoghq.okio:okio") // embed our patched fork
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,22 +2,20 @@

import static java.nio.charset.StandardCharsets.UTF_8;

import datadog.cli.CLIHelper;
import de.thetaphi.forbiddenapis.SuppressForbidden;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.lang.instrument.Instrumentation;
import java.lang.management.ManagementFactory;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.security.CodeSource;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.IdentityHashMap;
import java.util.List;
Expand Down Expand Up @@ -383,7 +381,7 @@ private static List<File> getAgentFilesFromVMArguments() {
// - 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~
for (final String argument : getVMArgumentsThroughReflection()) {
for (final String argument : CLIHelper.ARGS.getJvmArgs()) {
if (argument.startsWith(JAVA_AGENT_ARGUMENT)) {
int index = argument.indexOf('=', JAVA_AGENT_ARGUMENT.length());
String agentPathname =
Expand Down Expand Up @@ -424,57 +422,6 @@ private static File getAgentFileUsingClassLoaderLookup() throws URISyntaxExcepti
return javaagentFile;
}

@SuppressForbidden
private static List<String> getVMArgumentsThroughReflection() {
// Try Oracle-based
// IBM Semeru Runtime 1.8.0_345-b01 will throw UnsatisfiedLinkError here.
try {
final Class<?> managementFactoryHelperClass =
Class.forName("sun.management.ManagementFactoryHelper");

final Class<?> vmManagementClass = Class.forName("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);
}

//noinspection unchecked
return (List<String>) vmManagementClass.getMethod("getVmArguments").invoke(vmManagement);
} catch (final ReflectiveOperationException | UnsatisfiedLinkError ignored) {
// Ignored exception
}

// Try IBM-based.
try {
final Class<?> VMClass = Class.forName("com.ibm.oti.vm.VM");
final String[] argArray = (String[]) VMClass.getMethod("getVMArgs").invoke(null);
return Arrays.asList(argArray);
} catch (final ReflectiveOperationException ignored) {
// Ignored exception
}

// Fallback to default
try {
System.err.println(
"WARNING: Unable to get VM args through reflection. A custom java.util.logging.LogManager may not work correctly");
return ManagementFactory.getRuntimeMXBean().getInputArguments();
} catch (final Throwable t) {
// Throws InvocationTargetException on modularized applications
// with non-opened java.management module
System.err.println("WARNING: Unable to get VM args using managed beans");
}
return Collections.emptyList();
}

private static void checkJarManifestMainClassIsThis(final URL jarUrl) throws IOException {
final URL manifestUrl = new URL("jar:" + jarUrl + "!/META-INF/MANIFEST.MF");
final String mainClassLine = "Main-Class: " + thisClass.getCanonicalName();
Expand Down
1 change: 1 addition & 0 deletions settings.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ include ':dd-java-agent:agent-otel:otel-shim'
include ':dd-java-agent:agent-otel:otel-tooling'

include ':communication'
include ':components:cli'
include ':components:context'
include ':components:json'
include ':telemetry'
Expand Down
Loading