diff --git a/components/environment/build.gradle.kts b/components/environment/build.gradle.kts index c8c280e6b26..0b620c76090 100644 --- a/components/environment/build.gradle.kts +++ b/components/environment/build.gradle.kts @@ -23,7 +23,7 @@ val excludedClassesCoverage by extra { "datadog.environment.JavaVirtualMachine", // depends on OS and JVM vendor "datadog.environment.JavaVirtualMachine.JvmOptionsHolder", // depends on OS and JVM vendor "datadog.environment.JvmOptions", // depends on OS and JVM vendor - "datadog.environment.OperatingSystem", // depends on OS + "datadog.environment.OperatingSystem**", // depends on OS ) } val excludedClassesBranchCoverage by extra { diff --git a/components/environment/src/main/java/datadog/environment/OperatingSystem.java b/components/environment/src/main/java/datadog/environment/OperatingSystem.java index 06c72bad553..1d24d7680c9 100644 --- a/components/environment/src/main/java/datadog/environment/OperatingSystem.java +++ b/components/environment/src/main/java/datadog/environment/OperatingSystem.java @@ -1,5 +1,8 @@ package datadog.environment; +import static datadog.environment.OperatingSystem.Type.LINUX; +import static datadog.environment.OperatingSystem.Type.MACOS; +import static datadog.environment.OperatingSystem.Type.WINDOWS; import static java.util.Locale.ROOT; import java.io.BufferedReader; @@ -10,11 +13,15 @@ import java.nio.file.Path; import java.nio.file.Paths; import java.util.Arrays; +import java.util.HashSet; +import java.util.Set; /** Detects operating systems and libc library. */ public final class OperatingSystem { private static final String OS_NAME_PROPERTY = "os.name"; private static final String OS_ARCH_PROPERTY = "os.arch"; + private static final Type TYPE = Type.current(); + private static final Architecture ARCHITECTURE = Architecture.current(); private OperatingSystem() {} @@ -24,7 +31,7 @@ private OperatingSystem() {} * @return @{@code true} if operating system is Linux based, {@code false} otherwise. */ public static boolean isLinux() { - return propertyContains(OS_NAME_PROPERTY, "linux"); + return TYPE == LINUX; } /** @@ -33,8 +40,7 @@ public static boolean isLinux() { * @return @{@code true} if operating system is Windows, {@code false} otherwise. */ public static boolean isWindows() { - // https://mkyong.com/java/how-to-detect-os-in-java-systemgetpropertyosname/ - return propertyContains(OS_NAME_PROPERTY, "win"); + return TYPE == WINDOWS; } /** @@ -43,20 +49,21 @@ public static boolean isWindows() { * @return @{@code true} if operating system is macOS, {@code false} otherwise. */ public static boolean isMacOs() { - return propertyContains(OS_NAME_PROPERTY, "mac"); + return TYPE == MACOS; } /** - * Checks whether the architecture is AArch64. + * Gets the operating system type. * - * @return {@code true} if the architecture is AArch64, {@code false} otherwise. + * @return The operating system type, {@link Type#UNKNOWN} if not properly detected or supported. */ - public static boolean isAarch64() { - return propertyContains(OS_ARCH_PROPERTY, "aarch64"); + public static Type type() { + return TYPE; } - private static boolean propertyContains(String property, String content) { - return SystemProperties.getOrDefault(property, "").toLowerCase(ROOT).contains(content); + /** Gets the operating system architecture . */ + public static Architecture architecture() { + return ARCHITECTURE; } /** @@ -146,4 +153,65 @@ private static boolean containsArray(byte[] container, int offset, byte[] contai } return true; } + + public enum Type { + WINDOWS("Windows"), + MACOS("MacOS"), + LINUX("Linux"), + UNKNOWN("unknown"); + + private final String name; + + Type(String name) { + this.name = name; + } + + static Type current() { + String property = SystemProperties.getOrDefault(OS_NAME_PROPERTY, "").toLowerCase(ROOT); + // https://mkyong.com/java/how-to-detect-os-in-java-systemgetpropertyosname/ + if (property.contains("linux")) { + return LINUX; + } else if (property.contains("win")) { + return WINDOWS; + } else if (property.contains("mac")) { + return MACOS; + } else { + return UNKNOWN; + } + } + + @Override + public String toString() { + return this.name; + } + } + + /** Detects the operating system architecture. */ + public enum Architecture { + X64("x86_64", "amd64", "k8"), + X86("x86", "i386", "i486", "i586", "i686"), + ARM("arm", "aarch32"), + ARM64("arm64", "aarch64"), + UNKNOWN(); + + private final Set identifiers; + + Architecture(String... identifiers) { + this.identifiers = new HashSet<>(Arrays.asList(identifiers)); + } + + static Architecture of(String identifier) { + for (Architecture architecture : Architecture.values()) { + if (architecture.identifiers.contains(identifier)) { + return architecture; + } + } + return UNKNOWN; + } + + static Architecture current() { + String property = SystemProperties.getOrDefault(OS_ARCH_PROPERTY, "").toLowerCase(ROOT); + return Architecture.of(property); + } + } } diff --git a/components/environment/src/test/java/datadog/environment/OperatingSystemTest.java b/components/environment/src/test/java/datadog/environment/OperatingSystemTest.java index 5dc4a355546..ff5bbe9b871 100644 --- a/components/environment/src/test/java/datadog/environment/OperatingSystemTest.java +++ b/components/environment/src/test/java/datadog/environment/OperatingSystemTest.java @@ -1,11 +1,17 @@ package datadog.environment; +import static datadog.environment.OperatingSystem.Architecture.ARM; +import static datadog.environment.OperatingSystem.Architecture.ARM64; +import static datadog.environment.OperatingSystem.Architecture.X64; +import static datadog.environment.OperatingSystem.Architecture.X86; +import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.jupiter.api.condition.OS.LINUX; import static org.junit.jupiter.api.condition.OS.MAC; import static org.junit.jupiter.api.condition.OS.WINDOWS; +import datadog.environment.OperatingSystem.Type; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.condition.EnabledOnOs; @@ -16,6 +22,7 @@ void onLinuxOnly() { assertTrue(OperatingSystem.isLinux()); assertFalse(OperatingSystem.isMacOs()); assertFalse(OperatingSystem.isWindows()); + assertEquals(Type.LINUX, OperatingSystem.type()); } @Test @@ -24,6 +31,7 @@ void onMacOsOnly() { assertFalse(OperatingSystem.isLinux()); assertTrue(OperatingSystem.isMacOs()); assertFalse(OperatingSystem.isWindows()); + assertEquals(Type.MACOS, OperatingSystem.type()); } @Test @@ -32,5 +40,30 @@ void onWindowsOnly() { assertFalse(OperatingSystem.isLinux()); assertFalse(OperatingSystem.isMacOs()); assertTrue(OperatingSystem.isWindows()); + assertEquals(Type.WINDOWS, OperatingSystem.type()); + } + + @Test + @EnabledOnOs(architectures = {"x86_64", "amd64", "k8"}) + void onX64() { + assertEquals(X64, OperatingSystem.architecture()); + } + + @Test + @EnabledOnOs(architectures = {"x86", "i386", "i486", "i586", "i686"}) + void onX86() { + assertEquals(X86, OperatingSystem.architecture()); + } + + @Test + @EnabledOnOs(architectures = {"arm", "aarch32"}) + void onArm() { + assertEquals(ARM, OperatingSystem.architecture()); + } + + @Test + @EnabledOnOs(architectures = {"arm64", "aarch64"}) + void onArm64() { + assertEquals(ARM64, OperatingSystem.architecture()); } } diff --git a/dd-java-agent/agent-profiling/profiling-controller/src/main/java/com/datadog/profiling/controller/EnvironmentChecker.java b/dd-java-agent/agent-profiling/profiling-controller/src/main/java/com/datadog/profiling/controller/EnvironmentChecker.java index 6d4a6e3019e..2d8a4979938 100644 --- a/dd-java-agent/agent-profiling/profiling-controller/src/main/java/com/datadog/profiling/controller/EnvironmentChecker.java +++ b/dd-java-agent/agent-profiling/profiling-controller/src/main/java/com/datadog/profiling/controller/EnvironmentChecker.java @@ -1,5 +1,7 @@ package com.datadog.profiling.controller; +import static datadog.environment.OperatingSystem.Architecture.ARM64; + import datadog.environment.JavaVirtualMachine; import datadog.environment.OperatingSystem; import datadog.environment.SystemProperties; @@ -242,7 +244,10 @@ private static boolean extractSoFromJar(Path target, StringBuilder sb) throws Ex .filter( e -> e.getName() - .contains(OperatingSystem.isAarch64() ? "/linux-arm64/" : "/linux-x64/") + .contains( + OperatingSystem.architecture() == ARM64 + ? "/linux-arm64/" + : "/linux-x64/") && (!OperatingSystem.isMusl() || e.getName().contains("-musl"))) .findFirst() .map( diff --git a/dd-java-agent/agent-profiling/profiling-ddprof/src/main/java/com/datadog/profiling/ddprof/Arch.java b/dd-java-agent/agent-profiling/profiling-ddprof/src/main/java/com/datadog/profiling/ddprof/Arch.java deleted file mode 100644 index a1f1bb4dd1e..00000000000 --- a/dd-java-agent/agent-profiling/profiling-ddprof/src/main/java/com/datadog/profiling/ddprof/Arch.java +++ /dev/null @@ -1,35 +0,0 @@ -package com.datadog.profiling.ddprof; - -import datadog.environment.SystemProperties; -import java.util.Arrays; -import java.util.EnumSet; -import java.util.HashSet; -import java.util.Set; - -/** A simple implementation to detect the current architecture */ -public enum Arch { - x64("x86_64", "amd64", "k8"), - x86("x86", "i386", "i486", "i586", "i686"), - arm("ARM", "aarch32"), - arm64("arm64", "aarch64"), - unknown(); - - private final Set identifiers; - - Arch(String... identifiers) { - this.identifiers = new HashSet<>(Arrays.asList(identifiers)); - } - - public static Arch of(String identifier) { - for (Arch arch : EnumSet.allOf(Arch.class)) { - if (arch.identifiers.contains(identifier)) { - return arch; - } - } - return unknown; - } - - public static Arch current() { - return Arch.of(SystemProperties.get("os.arch")); - } -} diff --git a/dd-java-agent/agent-profiling/profiling-ddprof/src/main/java/com/datadog/profiling/ddprof/OperatingSystem.java b/dd-java-agent/agent-profiling/profiling-ddprof/src/main/java/com/datadog/profiling/ddprof/OperatingSystem.java deleted file mode 100644 index d0443533933..00000000000 --- a/dd-java-agent/agent-profiling/profiling-ddprof/src/main/java/com/datadog/profiling/ddprof/OperatingSystem.java +++ /dev/null @@ -1,33 +0,0 @@ -package com.datadog.profiling.ddprof; - -import datadog.environment.SystemProperties; -import java.util.Arrays; -import java.util.EnumSet; -import java.util.HashSet; -import java.util.Set; - -/** A simple way to detect the current operating system */ -public enum OperatingSystem { - linux("Linux", "linux"), - macos("Mac OS X", "macOS", "mac"), - unknown(); - - private final Set identifiers; - - OperatingSystem(String... identifiers) { - this.identifiers = new HashSet<>(Arrays.asList(identifiers)); - } - - public static OperatingSystem of(String identifier) { - for (OperatingSystem os : EnumSet.allOf(OperatingSystem.class)) { - if (os.identifiers.contains(identifier)) { - return os; - } - } - return unknown; - } - - public static OperatingSystem current() { - return OperatingSystem.of(SystemProperties.get("os.name")); - } -} diff --git a/dd-java-agent/agent-profiling/src/main/java/com/datadog/profiling/agent/CompositeController.java b/dd-java-agent/agent-profiling/src/main/java/com/datadog/profiling/agent/CompositeController.java index 0a7c100341b..5cec160a754 100644 --- a/dd-java-agent/agent-profiling/src/main/java/com/datadog/profiling/agent/CompositeController.java +++ b/dd-java-agent/agent-profiling/src/main/java/com/datadog/profiling/agent/CompositeController.java @@ -11,9 +11,8 @@ import com.datadog.profiling.controller.ddprof.DatadogProfilerController; import com.datadog.profiling.controller.openjdk.OpenJdkController; import com.datadog.profiling.controller.oracle.OracleJdkController; -import com.datadog.profiling.ddprof.Arch; -import com.datadog.profiling.ddprof.OperatingSystem; import datadog.environment.JavaVirtualMachine; +import datadog.environment.OperatingSystem; import datadog.environment.SystemProperties; import datadog.trace.api.Config; import datadog.trace.api.Platform; @@ -168,8 +167,8 @@ public static Controller build(ConfigProvider provider, ControllerContext contex ProfilerFlareLogger.getInstance() .log( "JFR is not available on this platform: {}, {}", - OperatingSystem.current(), - Arch.current()); + OperatingSystem.type(), + OperatingSystem.architecture()); } } catch (Throwable t) { ProfilerFlareLogger.getInstance().log("Failed to load openjdk profiler", t); @@ -186,14 +185,16 @@ public static Controller build(ConfigProvider provider, ControllerContext contex } catch (Throwable error) { Throwable rootCause = error.getCause() == null ? error : error.getCause(); context.setDatadogProfilerUnavailableReason(rootCause.getMessage()); - OperatingSystem os = OperatingSystem.current(); - if (os != OperatingSystem.linux) { + if (!isLinux()) { ProfilerFlareLogger.getInstance() .log("Datadog profiler only supported on Linux", rootCause); } else { ProfilerFlareLogger.getInstance() .log( - "Failed to instantiate Datadog profiler on {} {}", os, Arch.current(), rootCause); + "Failed to instantiate Datadog profiler on {} {}", + OperatingSystem.type(), + OperatingSystem.architecture(), + rootCause); } } } else { diff --git a/dd-java-agent/instrumentation/graal/native-image/src/main/java/datadog/trace/instrumentation/graal/nativeimage/NativeImageGeneratorRunnerInstrumentation.java b/dd-java-agent/instrumentation/graal/native-image/src/main/java/datadog/trace/instrumentation/graal/nativeimage/NativeImageGeneratorRunnerInstrumentation.java index 2ccf55418ec..7281ca41b36 100644 --- a/dd-java-agent/instrumentation/graal/native-image/src/main/java/datadog/trace/instrumentation/graal/nativeimage/NativeImageGeneratorRunnerInstrumentation.java +++ b/dd-java-agent/instrumentation/graal/native-image/src/main/java/datadog/trace/instrumentation/graal/nativeimage/NativeImageGeneratorRunnerInstrumentation.java @@ -72,6 +72,8 @@ public static void onEnter(@Advice.Argument(value = 0, readOnly = false) String[ + "com.datadog.profiling.controller.openjdk.events.SmapEntryFactory$SmapParseErrorEvent:build_time," + "com.datadog.profiling.ddprof.JavaProfilerLoader:run_time," + "datadog.environment.JavaVirtualMachine:rerun," + + "datadog.environment.OperatingSystem:rerun," + + "datadog.environment.OperatingSystem$Architecture:rerun," + "datadog.trace.agent.tooling.WeakMaps$Adapter:build_time," + "datadog.trace.api.Config:rerun," + "datadog.trace.api.Platform:rerun," diff --git a/dd-trace-core/src/main/java/datadog/trace/common/writer/TraceStructureWriter.java b/dd-trace-core/src/main/java/datadog/trace/common/writer/TraceStructureWriter.java index 6e1984a87f4..afeaebf2772 100644 --- a/dd-trace-core/src/main/java/datadog/trace/common/writer/TraceStructureWriter.java +++ b/dd-trace-core/src/main/java/datadog/trace/common/writer/TraceStructureWriter.java @@ -79,9 +79,14 @@ public TraceStructureWriter(String outputFile, boolean debugLog) { } private static String[] parseArgs(String outputFile) { + return parseArgs(outputFile, OperatingSystem.isWindows()); + } + + // package visibility for testing + static String[] parseArgs(String outputFile, boolean windows) { String[] args = ARGS_DELIMITER.split(outputFile); // Check Windows absolute paths (:) as column is used as arg delimiter - if (OperatingSystem.isWindows() + if (windows && args.length > 1 && args[0].length() == 1 && (args[1].startsWith("\\") || args[1].startsWith("/"))) { diff --git a/dd-trace-core/src/test/groovy/datadog/trace/api/writer/TraceStructureWriterTest.groovy b/dd-trace-core/src/test/groovy/datadog/trace/api/writer/TraceStructureWriterTest.groovy index 49ffc7e0b72..00dd1fe65dd 100644 --- a/dd-trace-core/src/test/groovy/datadog/trace/api/writer/TraceStructureWriterTest.groovy +++ b/dd-trace-core/src/test/groovy/datadog/trace/api/writer/TraceStructureWriterTest.groovy @@ -7,24 +7,23 @@ import datadog.trace.core.test.DDCoreSpecification class TraceStructureWriterTest extends DDCoreSpecification { def "parse CLI args"() { when: - System.setProperty("os.name", osName) - def args = TraceStructureWriter.parseArgs(cli) + def args = TraceStructureWriter.parseArgs(cli, windows) then: args.length > 0 args[0] == path where: - osName | cli | path - 'Windows' | 'C:/tmp/file' | 'C:/tmp/file' - 'Windows' | 'C:\\tmp\\file' | 'C:\\tmp\\file' - 'Windows' | 'file' | 'file' - 'Windows' | 'C:/tmp/file:includeresource' | 'C:/tmp/file' - 'Windows' | 'C:\\tmp\\file:includeresource' | 'C:\\tmp\\file' - 'Windows' | 'file:includeresource' | 'file' - 'Linux' | '/var/tmp/file' | '/var/tmp/file' - 'Linux' | 'file' | 'file' - 'MacOS' | '/var/tmp/file' | '/var/tmp/file' - 'MacOS' | 'file' | 'file' + windows | cli | path + true | 'C:/tmp/file' | 'C:/tmp/file' + true | 'C:\\tmp\\file' | 'C:\\tmp\\file' + true | 'file' | 'file' + true | 'C:/tmp/file:includeresource' | 'C:/tmp/file' + true | 'C:\\tmp\\file:includeresource' | 'C:\\tmp\\file' + true | 'file:includeresource' | 'file' + false | '/var/tmp/file' | '/var/tmp/file' + false | 'file' | 'file' + false | '/var/tmp/file' | '/var/tmp/file' + false | 'file' | 'file' } }