Skip to content
Merged
Show file tree
Hide file tree
Changes from 8 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 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;
Comment thread
mcculls marked this conversation as resolved.
Outdated

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

public HashSet<String> getJvmArgs() {
Comment thread
mcculls marked this conversation as resolved.
Outdated
return this.args;
}

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

private static List<String> 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();
} 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 {
// Read /proc/[pid]/cmdline to get JVM arguments
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"));
Comment thread
mcculls marked this conversation as resolved.
Outdated
} 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;
Comment thread
mtoffl01 marked this conversation as resolved.
Outdated
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 : cli.ARGS.getJvmArgs()) {
Comment thread
mtoffl01 marked this conversation as resolved.
Outdated
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