From a9d44005b362045881bd0b436af0b1eb1a428968 Mon Sep 17 00:00:00 2001 From: Mikayla Toffler Date: Mon, 10 Mar 2025 14:57:24 -0400 Subject: [PATCH 01/14] Abstract away getVMArgumentsThroughReflection into a VMArgsCache class --- .../trace/bootstrap/AgentBootstrap.java | 57 +----------- .../config/provider/VMArgsCache.java | 93 +++++++++++++++++++ 2 files changed, 95 insertions(+), 55 deletions(-) create mode 100644 internal-api/src/main/java/datadog/trace/bootstrap/config/provider/VMArgsCache.java diff --git a/dd-java-agent/src/main/java/datadog/trace/bootstrap/AgentBootstrap.java b/dd-java-agent/src/main/java/datadog/trace/bootstrap/AgentBootstrap.java index 095db7acc8c..d5d78f3b1b0 100644 --- a/dd-java-agent/src/main/java/datadog/trace/bootstrap/AgentBootstrap.java +++ b/dd-java-agent/src/main/java/datadog/trace/bootstrap/AgentBootstrap.java @@ -2,6 +2,7 @@ import static java.nio.charset.StandardCharsets.UTF_8; +import datadog.trace.bootstrap.config.provider.VMArgsCache; import de.thetaphi.forbiddenapis.SuppressForbidden; import java.io.BufferedReader; import java.io.File; @@ -9,15 +10,12 @@ 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; @@ -383,7 +381,7 @@ private static List 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 : VMArgsCache.getVMArguments()) { if (argument.startsWith(JAVA_AGENT_ARGUMENT)) { int index = argument.indexOf('=', JAVA_AGENT_ARGUMENT.length()); String agentPathname = @@ -424,57 +422,6 @@ private static File getAgentFileUsingClassLoaderLookup() throws URISyntaxExcepti return javaagentFile; } - @SuppressForbidden - private static List 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) 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(); diff --git a/internal-api/src/main/java/datadog/trace/bootstrap/config/provider/VMArgsCache.java b/internal-api/src/main/java/datadog/trace/bootstrap/config/provider/VMArgsCache.java new file mode 100644 index 00000000000..3ad906dd3eb --- /dev/null +++ b/internal-api/src/main/java/datadog/trace/bootstrap/config/provider/VMArgsCache.java @@ -0,0 +1,93 @@ +package datadog.trace.bootstrap.config.provider; + +import de.thetaphi.forbiddenapis.SuppressForbidden; +import java.lang.management.ManagementFactory; +import java.lang.reflect.Field; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +public class VMArgsCache { + private static final class Singleton { + private static VMArgsCache INSTANCE = null; + } + + // TODO: Make this a smarter data structure + private final List args; + private boolean initialized; + + public VMArgsCache(List args) { + this.args = args; + } + + public List getArgs() { + return this.args; + } + + public boolean contains(String argument) { + for (String arg : this.args) { + if (arg.equals(argument)) { + return true; + } + } + return false; + } + + @SuppressForbidden + public static List getVMArguments() { + if (Singleton.INSTANCE == null) { + Singleton.INSTANCE = new VMArgsCache(getVMArgumentsThroughReflection()); + } + return Singleton.INSTANCE.getArgs(); + } + + private static List 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) 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(); + } +} From d688313da80638080f10ab79dad3041f7f5f17f9 Mon Sep 17 00:00:00 2001 From: Mikayla Toffler Date: Tue, 11 Mar 2025 16:27:28 -0400 Subject: [PATCH 02/14] Change underlying data structure of VMArgsCache to HashSet --- .../config/provider/VMArgsCache.java | 67 ++++++++++++++----- 1 file changed, 51 insertions(+), 16 deletions(-) diff --git a/internal-api/src/main/java/datadog/trace/bootstrap/config/provider/VMArgsCache.java b/internal-api/src/main/java/datadog/trace/bootstrap/config/provider/VMArgsCache.java index 3ad906dd3eb..7011570a53c 100644 --- a/internal-api/src/main/java/datadog/trace/bootstrap/config/provider/VMArgsCache.java +++ b/internal-api/src/main/java/datadog/trace/bootstrap/config/provider/VMArgsCache.java @@ -1,47 +1,54 @@ package datadog.trace.bootstrap.config.provider; 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 VMArgsCache { private static final class Singleton { - private static VMArgsCache INSTANCE = null; + private static final VMArgsCache INSTANCE = new VMArgsCache(getVMArgumentsThroughReflection()); } - // TODO: Make this a smarter data structure - private final List args; - private boolean initialized; + private final HashSet args; public VMArgsCache(List args) { - this.args = args; + this.args = new HashSet<>(args); } - public List getArgs() { + private HashSet getArgs() { return this.args; } public boolean contains(String argument) { - for (String arg : this.args) { - if (arg.equals(argument)) { - return true; - } - } - return false; + return this.args.contains(argument); } @SuppressForbidden - public static List getVMArguments() { - if (Singleton.INSTANCE == null) { - Singleton.INSTANCE = new VMArgsCache(getVMArgumentsThroughReflection()); - } + public static HashSet getVMArguments() { return Singleton.INSTANCE.getArgs(); } private static List getVMArgumentsThroughReflection() { + // TODO: equals, or contains? + if (System.getProperty("os.name").equalsIgnoreCase("linux")) { + // Get the current process PID from /proc/self/status + try { + String pid = getPidFromProcStatus(); + if (pid != null) { + // Get the JVM arguments from /proc/[pid]/cmdline + return getJvmArgsFromProcCmdline(pid); + } + } catch (IOException e) { + // ignore exception, try other methods + } + } // Try Oracle-based // IBM Semeru Runtime 1.8.0_345-b01 will throw UnsatisfiedLinkError here. try { @@ -90,4 +97,32 @@ private static List getVMArgumentsThroughReflection() { } return Collections.emptyList(); } + + // Helper methods for getting process information from linux proc dir + private static String getPidFromProcStatus() throws IOException { + String pid = null; + // Read /proc/self/status to find the current process's PID + try (BufferedReader pidReader = new BufferedReader(new FileReader("/proc/self/status"))) { + String line; + while ((line = pidReader.readLine()) != null) { + if (line.startsWith("Pid:")) { + pid = line.split(":")[1].trim(); + break; + } + } + } + return pid; + } + + private static List getJvmArgsFromProcCmdline(String pid) throws IOException { + // Read /proc/[pid]/cmdline to get JVM arguments + BufferedReader argsReader = new BufferedReader(new FileReader("/proc/" + pid + "/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; + } + } } From d6344a8a8ee9cd82b722ed94a6d9405a444703b4 Mon Sep 17 00:00:00 2001 From: Mikayla Toffler <46911781+mtoffl01@users.noreply.github.com> Date: Tue, 11 Mar 2025 16:32:12 -0400 Subject: [PATCH 03/14] Update internal-api/src/main/java/datadog/trace/bootstrap/config/provider/VMArgsCache.java Co-authored-by: datadog-datadog-prod-us1[bot] <88084959+datadog-datadog-prod-us1[bot]@users.noreply.github.com> --- .../datadog/trace/bootstrap/config/provider/VMArgsCache.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal-api/src/main/java/datadog/trace/bootstrap/config/provider/VMArgsCache.java b/internal-api/src/main/java/datadog/trace/bootstrap/config/provider/VMArgsCache.java index 7011570a53c..60bd4543b33 100644 --- a/internal-api/src/main/java/datadog/trace/bootstrap/config/provider/VMArgsCache.java +++ b/internal-api/src/main/java/datadog/trace/bootstrap/config/provider/VMArgsCache.java @@ -16,7 +16,7 @@ private static final class Singleton { private static final VMArgsCache INSTANCE = new VMArgsCache(getVMArgumentsThroughReflection()); } - private final HashSet args; + private final Set args; public VMArgsCache(List args) { this.args = new HashSet<>(args); From 6aba3f86159e44529a326e4eb85687c4bc8cf5fc Mon Sep 17 00:00:00 2001 From: Mikayla Toffler <46911781+mtoffl01@users.noreply.github.com> Date: Tue, 11 Mar 2025 16:32:19 -0400 Subject: [PATCH 04/14] Update internal-api/src/main/java/datadog/trace/bootstrap/config/provider/VMArgsCache.java Co-authored-by: datadog-datadog-prod-us1[bot] <88084959+datadog-datadog-prod-us1[bot]@users.noreply.github.com> --- .../datadog/trace/bootstrap/config/provider/VMArgsCache.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal-api/src/main/java/datadog/trace/bootstrap/config/provider/VMArgsCache.java b/internal-api/src/main/java/datadog/trace/bootstrap/config/provider/VMArgsCache.java index 60bd4543b33..d040430ead2 100644 --- a/internal-api/src/main/java/datadog/trace/bootstrap/config/provider/VMArgsCache.java +++ b/internal-api/src/main/java/datadog/trace/bootstrap/config/provider/VMArgsCache.java @@ -22,7 +22,7 @@ public VMArgsCache(List args) { this.args = new HashSet<>(args); } - private HashSet getArgs() { + private Set getArgs() { return this.args; } From 8afbec1143f524a1cbc2ecf5d07e8b8817b8cc33 Mon Sep 17 00:00:00 2001 From: Mikayla Toffler <46911781+mtoffl01@users.noreply.github.com> Date: Tue, 11 Mar 2025 16:32:29 -0400 Subject: [PATCH 05/14] Update internal-api/src/main/java/datadog/trace/bootstrap/config/provider/VMArgsCache.java Co-authored-by: datadog-datadog-prod-us1[bot] <88084959+datadog-datadog-prod-us1[bot]@users.noreply.github.com> --- .../datadog/trace/bootstrap/config/provider/VMArgsCache.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal-api/src/main/java/datadog/trace/bootstrap/config/provider/VMArgsCache.java b/internal-api/src/main/java/datadog/trace/bootstrap/config/provider/VMArgsCache.java index d040430ead2..676f43a25bb 100644 --- a/internal-api/src/main/java/datadog/trace/bootstrap/config/provider/VMArgsCache.java +++ b/internal-api/src/main/java/datadog/trace/bootstrap/config/provider/VMArgsCache.java @@ -31,7 +31,7 @@ public boolean contains(String argument) { } @SuppressForbidden - public static HashSet getVMArguments() { + public static Set getVMArguments() { return Singleton.INSTANCE.getArgs(); } From d807b02655172e6ad24fcb8b638e33400a9c2056 Mon Sep 17 00:00:00 2001 From: Mikayla Toffler Date: Wed, 12 Mar 2025 13:15:31 -0400 Subject: [PATCH 06/14] Clean up for initial review --- .../datadog/trace/bootstrap/AgentBootstrap.java | 2 +- .../bootstrap/config/provider/VMArgsCache.java | 16 +++++----------- 2 files changed, 6 insertions(+), 12 deletions(-) diff --git a/dd-java-agent/src/main/java/datadog/trace/bootstrap/AgentBootstrap.java b/dd-java-agent/src/main/java/datadog/trace/bootstrap/AgentBootstrap.java index d5d78f3b1b0..0ae3874dd77 100644 --- a/dd-java-agent/src/main/java/datadog/trace/bootstrap/AgentBootstrap.java +++ b/dd-java-agent/src/main/java/datadog/trace/bootstrap/AgentBootstrap.java @@ -381,7 +381,7 @@ private static List 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 : VMArgsCache.getVMArguments()) { + for (final String argument : VMArgsCache.ARGS.getJvmArgs()) { if (argument.startsWith(JAVA_AGENT_ARGUMENT)) { int index = argument.indexOf('=', JAVA_AGENT_ARGUMENT.length()); String agentPathname = diff --git a/internal-api/src/main/java/datadog/trace/bootstrap/config/provider/VMArgsCache.java b/internal-api/src/main/java/datadog/trace/bootstrap/config/provider/VMArgsCache.java index 7011570a53c..cac246e31d6 100644 --- a/internal-api/src/main/java/datadog/trace/bootstrap/config/provider/VMArgsCache.java +++ b/internal-api/src/main/java/datadog/trace/bootstrap/config/provider/VMArgsCache.java @@ -1,6 +1,5 @@ package datadog.trace.bootstrap.config.provider; -import de.thetaphi.forbiddenapis.SuppressForbidden; import java.io.BufferedReader; import java.io.FileReader; import java.io.IOException; @@ -11,10 +10,9 @@ import java.util.HashSet; import java.util.List; +/** VMArgsCache stores JVM Arguments applied to the current process */ public class VMArgsCache { - private static final class Singleton { - private static final VMArgsCache INSTANCE = new VMArgsCache(getVMArgumentsThroughReflection()); - } + public static final VMArgsCache ARGS = new VMArgsCache(initJvmArgs()); private final HashSet args; @@ -22,7 +20,7 @@ public VMArgsCache(List args) { this.args = new HashSet<>(args); } - private HashSet getArgs() { + public HashSet getJvmArgs() { return this.args; } @@ -30,12 +28,8 @@ public boolean contains(String argument) { return this.args.contains(argument); } - @SuppressForbidden - public static HashSet getVMArguments() { - return Singleton.INSTANCE.getArgs(); - } - - private static List getVMArgumentsThroughReflection() { + private static List initJvmArgs() { + // If linux OS, use procfs // TODO: equals, or contains? if (System.getProperty("os.name").equalsIgnoreCase("linux")) { // Get the current process PID from /proc/self/status From 7ce49534699722d0186d1df21ab45769ac4fcbc0 Mon Sep 17 00:00:00 2001 From: Mikayla Toffler Date: Fri, 14 Mar 2025 11:48:00 -0400 Subject: [PATCH 07/14] move VMArgsCache to components/cli --- components/cli/build.gradle.kts | 9 +++++ .../src/main/java/datadog.cli/CLIHelper.java | 36 +++++-------------- dd-java-agent/build.gradle | 1 + .../trace/bootstrap/AgentBootstrap.java | 4 +-- settings.gradle | 1 + 5 files changed, 21 insertions(+), 30 deletions(-) create mode 100644 components/cli/build.gradle.kts rename internal-api/src/main/java/datadog/trace/bootstrap/config/provider/VMArgsCache.java => components/cli/src/main/java/datadog.cli/CLIHelper.java (73%) diff --git a/components/cli/build.gradle.kts b/components/cli/build.gradle.kts new file mode 100644 index 00000000000..4dca7fc3036 --- /dev/null +++ b/components/cli/build.gradle.kts @@ -0,0 +1,9 @@ +plugins { + id("me.champeau.jmh") +} + +apply(from = "$rootDir/gradle/java.gradle") + +jmh { + version = "1.28" +} diff --git a/internal-api/src/main/java/datadog/trace/bootstrap/config/provider/VMArgsCache.java b/components/cli/src/main/java/datadog.cli/CLIHelper.java similarity index 73% rename from internal-api/src/main/java/datadog/trace/bootstrap/config/provider/VMArgsCache.java rename to components/cli/src/main/java/datadog.cli/CLIHelper.java index cac246e31d6..e06250df3a4 100644 --- a/internal-api/src/main/java/datadog/trace/bootstrap/config/provider/VMArgsCache.java +++ b/components/cli/src/main/java/datadog.cli/CLIHelper.java @@ -1,4 +1,4 @@ -package datadog.trace.bootstrap.config.provider; +package datadog.cli; import java.io.BufferedReader; import java.io.FileReader; @@ -10,13 +10,12 @@ import java.util.HashSet; import java.util.List; -/** VMArgsCache stores JVM Arguments applied to the current process */ -public class VMArgsCache { - public static final VMArgsCache ARGS = new VMArgsCache(initJvmArgs()); +public class CLIHelper { + public static final CLIHelper ARGS = new CLIHelper(initJvmArgs()); private final HashSet args; - public VMArgsCache(List args) { + public CLIHelper(List args) { this.args = new HashSet<>(args); } @@ -34,11 +33,8 @@ private static List initJvmArgs() { if (System.getProperty("os.name").equalsIgnoreCase("linux")) { // Get the current process PID from /proc/self/status try { - String pid = getPidFromProcStatus(); - if (pid != null) { - // Get the JVM arguments from /proc/[pid]/cmdline - return getJvmArgsFromProcCmdline(pid); - } + // Get the JVM arguments from /proc/self/cmdline + return getJvmArgsFromProcCmdline(); } catch (IOException e) { // ignore exception, try other methods } @@ -92,25 +88,9 @@ private static List initJvmArgs() { return Collections.emptyList(); } - // Helper methods for getting process information from linux proc dir - private static String getPidFromProcStatus() throws IOException { - String pid = null; - // Read /proc/self/status to find the current process's PID - try (BufferedReader pidReader = new BufferedReader(new FileReader("/proc/self/status"))) { - String line; - while ((line = pidReader.readLine()) != null) { - if (line.startsWith("Pid:")) { - pid = line.split(":")[1].trim(); - break; - } - } - } - return pid; - } - - private static List getJvmArgsFromProcCmdline(String pid) throws IOException { + private static List getJvmArgsFromProcCmdline() throws IOException { // Read /proc/[pid]/cmdline to get JVM arguments - BufferedReader argsReader = new BufferedReader(new FileReader("/proc/" + pid + "/cmdline")); + 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 diff --git a/dd-java-agent/build.gradle b/dd-java-agent/build.gradle index 6528a2e3c2e..95737b79eeb 100644 --- a/dd-java-agent/build.gradle +++ b/dd-java-agent/build.gradle @@ -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 diff --git a/dd-java-agent/src/main/java/datadog/trace/bootstrap/AgentBootstrap.java b/dd-java-agent/src/main/java/datadog/trace/bootstrap/AgentBootstrap.java index 0ae3874dd77..107a5e827d2 100644 --- a/dd-java-agent/src/main/java/datadog/trace/bootstrap/AgentBootstrap.java +++ b/dd-java-agent/src/main/java/datadog/trace/bootstrap/AgentBootstrap.java @@ -2,7 +2,7 @@ import static java.nio.charset.StandardCharsets.UTF_8; -import datadog.trace.bootstrap.config.provider.VMArgsCache; +import datadog.cli; import de.thetaphi.forbiddenapis.SuppressForbidden; import java.io.BufferedReader; import java.io.File; @@ -381,7 +381,7 @@ private static List 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 : VMArgsCache.ARGS.getJvmArgs()) { + for (final String argument : cli.ARGS.getJvmArgs()) { if (argument.startsWith(JAVA_AGENT_ARGUMENT)) { int index = argument.indexOf('=', JAVA_AGENT_ARGUMENT.length()); String agentPathname = diff --git a/settings.gradle b/settings.gradle index 3ba7be61fe5..8dd42b9cab9 100644 --- a/settings.gradle +++ b/settings.gradle @@ -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' From 7a9f694eea8e0126bee1f7731f68298b4ee95107 Mon Sep 17 00:00:00 2001 From: Mikayla Toffler Date: Fri, 14 Mar 2025 12:06:22 -0400 Subject: [PATCH 08/14] fix datadog.cli import --- .../src/main/java/datadog/trace/bootstrap/AgentBootstrap.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dd-java-agent/src/main/java/datadog/trace/bootstrap/AgentBootstrap.java b/dd-java-agent/src/main/java/datadog/trace/bootstrap/AgentBootstrap.java index 107a5e827d2..d715c1f3277 100644 --- a/dd-java-agent/src/main/java/datadog/trace/bootstrap/AgentBootstrap.java +++ b/dd-java-agent/src/main/java/datadog/trace/bootstrap/AgentBootstrap.java @@ -2,7 +2,7 @@ import static java.nio.charset.StandardCharsets.UTF_8; -import datadog.cli; +import datadog.cli.CLIHelper; import de.thetaphi.forbiddenapis.SuppressForbidden; import java.io.BufferedReader; import java.io.File; @@ -381,7 +381,7 @@ private static List 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 : cli.ARGS.getJvmArgs()) { + for (final String argument : CLIHelper.ARGS.getJvmArgs()) { if (argument.startsWith(JAVA_AGENT_ARGUMENT)) { int index = argument.indexOf('=', JAVA_AGENT_ARGUMENT.length()); String agentPathname = From dd17ca24b359de701d892acb4695e13fad584c4e Mon Sep 17 00:00:00 2001 From: Mikayla Toffler Date: Fri, 14 Mar 2025 12:11:17 -0400 Subject: [PATCH 09/14] nits: remove outdated comments --- components/cli/src/main/java/datadog.cli/CLIHelper.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/components/cli/src/main/java/datadog.cli/CLIHelper.java b/components/cli/src/main/java/datadog.cli/CLIHelper.java index e06250df3a4..5befd50f71f 100644 --- a/components/cli/src/main/java/datadog.cli/CLIHelper.java +++ b/components/cli/src/main/java/datadog.cli/CLIHelper.java @@ -31,7 +31,6 @@ private static List initJvmArgs() { // If linux OS, use procfs // TODO: equals, or contains? if (System.getProperty("os.name").equalsIgnoreCase("linux")) { - // Get the current process PID from /proc/self/status try { // Get the JVM arguments from /proc/self/cmdline return getJvmArgsFromProcCmdline(); @@ -89,7 +88,6 @@ private static List initJvmArgs() { } private static List getJvmArgsFromProcCmdline() throws IOException { - // Read /proc/[pid]/cmdline to get JVM arguments BufferedReader argsReader = new BufferedReader(new FileReader("/proc/self/cmdline")); String cmdLine = argsReader.readLine(); if (cmdLine != null) { From 2798bed48a728273d1d027b737431a22aefd8b49 Mon Sep 17 00:00:00 2001 From: Mikayla Toffler Date: Mon, 17 Mar 2025 10:32:44 -0400 Subject: [PATCH 10/14] annotate initJvmArgs with @SuppressForbidden to allow Class.forName() usage --- components/cli/src/main/java/datadog.cli/CLIHelper.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/components/cli/src/main/java/datadog.cli/CLIHelper.java b/components/cli/src/main/java/datadog.cli/CLIHelper.java index 5befd50f71f..4fdfcc92e7d 100644 --- a/components/cli/src/main/java/datadog.cli/CLIHelper.java +++ b/components/cli/src/main/java/datadog.cli/CLIHelper.java @@ -1,5 +1,6 @@ package datadog.cli; +import de.thetaphi.forbiddenapis.SuppressForbidden; import java.io.BufferedReader; import java.io.FileReader; import java.io.IOException; @@ -27,6 +28,7 @@ public boolean contains(String argument) { return this.args.contains(argument); } + @SuppressForbidden private static List initJvmArgs() { // If linux OS, use procfs // TODO: equals, or contains? From 253e5e4aff84aa6a71387a78da6c8ef3816236bd Mon Sep 17 00:00:00 2001 From: Stuart McCulloch Date: Tue, 25 Mar 2025 12:35:53 +0000 Subject: [PATCH 11/14] Fix package directory --- .../cli/src/main/java/{datadog.cli => datadog/cli}/CLIHelper.java | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename components/cli/src/main/java/{datadog.cli => datadog/cli}/CLIHelper.java (100%) diff --git a/components/cli/src/main/java/datadog.cli/CLIHelper.java b/components/cli/src/main/java/datadog/cli/CLIHelper.java similarity index 100% rename from components/cli/src/main/java/datadog.cli/CLIHelper.java rename to components/cli/src/main/java/datadog/cli/CLIHelper.java From e67ae7a5bc5ac7392a8d3185f79cc5838c8618b4 Mon Sep 17 00:00:00 2001 From: Stuart McCulloch Date: Tue, 25 Mar 2025 13:23:11 +0000 Subject: [PATCH 12/14] Cleanup code: * store args in static field, make available via static getter * use list of strings as storage type to begin with * prefer NIO methods to read content (defaults to UTF8) * use try-with-resources to ensure reader is closed * check file exists as a quick short-circuit --- .../src/main/java/datadog/cli/CLIHelper.java | 58 ++++++++----------- .../trace/bootstrap/AgentBootstrap.java | 2 +- 2 files changed, 24 insertions(+), 36 deletions(-) diff --git a/components/cli/src/main/java/datadog/cli/CLIHelper.java b/components/cli/src/main/java/datadog/cli/CLIHelper.java index 4fdfcc92e7d..9dafb3089c4 100644 --- a/components/cli/src/main/java/datadog/cli/CLIHelper.java +++ b/components/cli/src/main/java/datadog/cli/CLIHelper.java @@ -2,44 +2,39 @@ 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.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; import java.util.Arrays; import java.util.Collections; -import java.util.HashSet; import java.util.List; +import java.util.Locale; -public class CLIHelper { - public static final CLIHelper ARGS = new CLIHelper(initJvmArgs()); +public final class CLIHelper { + private static final List VM_ARGS = findVmArgs(); - private final HashSet args; - - public CLIHelper(List args) { - this.args = new HashSet<>(args); - } - - public HashSet getJvmArgs() { - return this.args; - } - - public boolean contains(String argument) { - return this.args.contains(argument); + public static List getVmArgs() { + return VM_ARGS; } @SuppressForbidden - private static List 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 + private static List findVmArgs() { + // Try ProcFS on Linux + try { + if (isLinux()) { + Path cmdlinePath = Paths.get("/proc/self/cmdline"); + if (Files.exists(cmdlinePath)) { + try (BufferedReader in = Files.newBufferedReader(cmdlinePath)) { + return Arrays.asList(in.readLine().split("\0")); + } + } } + } catch (Throwable ignored) { + // Ignored exception } + // Try Oracle-based // IBM Semeru Runtime 1.8.0_345-b01 will throw UnsatisfiedLinkError here. try { @@ -89,14 +84,7 @@ private static List initJvmArgs() { return Collections.emptyList(); } - private static List 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; - } + private static boolean isLinux() { + return System.getProperty("os.name").toLowerCase(Locale.ROOT).contains("linux"); } } diff --git a/dd-java-agent/src/main/java/datadog/trace/bootstrap/AgentBootstrap.java b/dd-java-agent/src/main/java/datadog/trace/bootstrap/AgentBootstrap.java index d715c1f3277..f70038f26ba 100644 --- a/dd-java-agent/src/main/java/datadog/trace/bootstrap/AgentBootstrap.java +++ b/dd-java-agent/src/main/java/datadog/trace/bootstrap/AgentBootstrap.java @@ -381,7 +381,7 @@ private static List 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 : CLIHelper.ARGS.getJvmArgs()) { + for (final String argument : CLIHelper.getVmArgs()) { if (argument.startsWith(JAVA_AGENT_ARGUMENT)) { int index = argument.indexOf('=', JAVA_AGENT_ARGUMENT.length()); String agentPathname = From b8446073e89813d05bee7db20c055212819ecfc1 Mon Sep 17 00:00:00 2001 From: Stuart McCulloch Date: Tue, 25 Mar 2025 13:29:59 +0000 Subject: [PATCH 13/14] Remove warning when reflection fails --- components/cli/src/main/java/datadog/cli/CLIHelper.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/components/cli/src/main/java/datadog/cli/CLIHelper.java b/components/cli/src/main/java/datadog/cli/CLIHelper.java index 9dafb3089c4..0f37953a92f 100644 --- a/components/cli/src/main/java/datadog/cli/CLIHelper.java +++ b/components/cli/src/main/java/datadog/cli/CLIHelper.java @@ -73,8 +73,6 @@ private static List findVmArgs() { // 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 From 8837a21358853134281d98d81072842feedbd89c Mon Sep 17 00:00:00 2001 From: Stuart McCulloch Date: Tue, 25 Mar 2025 13:54:27 +0000 Subject: [PATCH 14/14] Expose components:cli from internal-api --- .../src/main/java/datadog/trace/bootstrap/Constants.java | 1 + .../src/main/groovy/datadog/trace/agent/test/SpockRunner.java | 1 + gradle/dependencies.gradle | 1 + internal-api/build.gradle | 1 + 4 files changed, 4 insertions(+) diff --git a/dd-java-agent/agent-bootstrap/src/main/java/datadog/trace/bootstrap/Constants.java b/dd-java-agent/agent-bootstrap/src/main/java/datadog/trace/bootstrap/Constants.java index c017f331181..0ed02193072 100644 --- a/dd-java-agent/agent-bootstrap/src/main/java/datadog/trace/bootstrap/Constants.java +++ b/dd-java-agent/agent-bootstrap/src/main/java/datadog/trace/bootstrap/Constants.java @@ -17,6 +17,7 @@ public final class Constants { "datadog.slf4j", "datadog.json", "datadog.context", + "datadog.cli", "datadog.appsec.api", "datadog.trace.api", "datadog.trace.bootstrap", diff --git a/dd-java-agent/testing/src/main/groovy/datadog/trace/agent/test/SpockRunner.java b/dd-java-agent/testing/src/main/groovy/datadog/trace/agent/test/SpockRunner.java index 684b5c4b11a..eda9e4d86d4 100644 --- a/dd-java-agent/testing/src/main/groovy/datadog/trace/agent/test/SpockRunner.java +++ b/dd-java-agent/testing/src/main/groovy/datadog/trace/agent/test/SpockRunner.java @@ -40,6 +40,7 @@ public class SpockRunner extends JUnitPlatform { "datadog.slf4j", "datadog.json", "datadog.context", + "datadog.cli", "datadog.appsec.api", "datadog.trace.api", "datadog.trace.bootstrap", diff --git a/gradle/dependencies.gradle b/gradle/dependencies.gradle index 2fd95f2c4af..76e8061f5d8 100644 --- a/gradle/dependencies.gradle +++ b/gradle/dependencies.gradle @@ -18,6 +18,7 @@ final class CachedData { exclude(project(':communication')) exclude(project(':components:context')) exclude(project(':components:json')) + exclude(project(':components:cli')) exclude(project(':remote-config:remote-config-api')) exclude(project(':remote-config:remote-config-core')) exclude(project(':telemetry')) diff --git a/internal-api/build.gradle b/internal-api/build.gradle index 947fe5d0ea8..9d0107ae991 100644 --- a/internal-api/build.gradle +++ b/internal-api/build.gradle @@ -234,6 +234,7 @@ dependencies { api project(':dd-trace-api') api libs.slf4j api project(':components:context') + api project(':components:cli') api project(":utils:time-utils") // has to be loaded by system classloader: