Skip to content

Commit d1f4a79

Browse files
committed
feat(env): Improve OS type and arch detection
1 parent a081948 commit d1f4a79

File tree

8 files changed

+150
-99
lines changed

8 files changed

+150
-99
lines changed

components/environment/build.gradle.kts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ val excludedClassesCoverage by extra {
2323
"datadog.environment.JavaVirtualMachine", // depends on OS and JVM vendor
2424
"datadog.environment.JavaVirtualMachine.JvmOptionsHolder", // depends on OS and JVM vendor
2525
"datadog.environment.JvmOptions", // depends on OS and JVM vendor
26-
"datadog.environment.OperatingSystem", // depends on OS
26+
"datadog.environment.OperatingSystem**", // depends on OS
2727
)
2828
}
2929
val excludedClassesBranchCoverage by extra {

components/environment/src/main/java/datadog/environment/OperatingSystem.java

Lines changed: 78 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
package datadog.environment;
22

3+
import static datadog.environment.OperatingSystem.Type.LINUX;
4+
import static datadog.environment.OperatingSystem.Type.MACOS;
5+
import static datadog.environment.OperatingSystem.Type.WINDOWS;
36
import static java.util.Locale.ROOT;
47

58
import java.io.BufferedReader;
@@ -10,11 +13,15 @@
1013
import java.nio.file.Path;
1114
import java.nio.file.Paths;
1215
import java.util.Arrays;
16+
import java.util.HashSet;
17+
import java.util.Set;
1318

1419
/** Detects operating systems and libc library. */
1520
public final class OperatingSystem {
1621
private static final String OS_NAME_PROPERTY = "os.name";
1722
private static final String OS_ARCH_PROPERTY = "os.arch";
23+
private static final Type TYPE = Type.current();
24+
private static final Architecture ARCHITECTURE = Architecture.current();
1825

1926
private OperatingSystem() {}
2027

@@ -24,7 +31,7 @@ private OperatingSystem() {}
2431
* @return @{@code true} if operating system is Linux based, {@code false} otherwise.
2532
*/
2633
public static boolean isLinux() {
27-
return propertyContains(OS_NAME_PROPERTY, "linux");
34+
return TYPE == LINUX;
2835
}
2936

3037
/**
@@ -33,8 +40,7 @@ public static boolean isLinux() {
3340
* @return @{@code true} if operating system is Windows, {@code false} otherwise.
3441
*/
3542
public static boolean isWindows() {
36-
// https://mkyong.com/java/how-to-detect-os-in-java-systemgetpropertyosname/
37-
return propertyContains(OS_NAME_PROPERTY, "win");
43+
return TYPE == WINDOWS;
3844
}
3945

4046
/**
@@ -43,20 +49,21 @@ public static boolean isWindows() {
4349
* @return @{@code true} if operating system is macOS, {@code false} otherwise.
4450
*/
4551
public static boolean isMacOs() {
46-
return propertyContains(OS_NAME_PROPERTY, "mac");
52+
return TYPE == MACOS;
4753
}
4854

4955
/**
50-
* Checks whether the architecture is AArch64.
56+
* Gets the operating system type.
5157
*
52-
* @return {@code true} if the architecture is AArch64, {@code false} otherwise.
58+
* @return The operating system type, {@link Type#UNKNOWN} if not properly detected or supported.
5359
*/
54-
public static boolean isAarch64() {
55-
return propertyContains(OS_ARCH_PROPERTY, "aarch64");
60+
public static Type type() {
61+
return TYPE;
5662
}
5763

58-
private static boolean propertyContains(String property, String content) {
59-
return SystemProperties.getOrDefault(property, "").toLowerCase(ROOT).contains(content);
64+
/** Gets the operating system architecture . */
65+
public static Architecture architecture() {
66+
return ARCHITECTURE;
6067
}
6168

6269
/**
@@ -146,4 +153,65 @@ private static boolean containsArray(byte[] container, int offset, byte[] contai
146153
}
147154
return true;
148155
}
156+
157+
public enum Type {
158+
WINDOWS("Windows"),
159+
MACOS("MacOS"),
160+
LINUX("Linux"),
161+
UNKNOWN("unknown");
162+
163+
private final String name;
164+
165+
Type(String name) {
166+
this.name = name;
167+
}
168+
169+
static Type current() {
170+
String property = SystemProperties.getOrDefault(OS_NAME_PROPERTY, "").toLowerCase(ROOT);
171+
// https://mkyong.com/java/how-to-detect-os-in-java-systemgetpropertyosname/
172+
if (property.contains("linux")) {
173+
return LINUX;
174+
} else if (property.contains("win")) {
175+
return WINDOWS;
176+
} else if (property.contains("mac")) {
177+
return MACOS;
178+
} else {
179+
return UNKNOWN;
180+
}
181+
}
182+
183+
@Override
184+
public String toString() {
185+
return this.name;
186+
}
187+
}
188+
189+
/** Detects the operating system architecture. */
190+
public enum Architecture {
191+
X64("x86_64", "amd64", "k8"),
192+
X86("x86", "i386", "i486", "i586", "i686"),
193+
ARM("arm", "aarch32"),
194+
ARM64("arm64", "aarch64"),
195+
UNKNOWN();
196+
197+
private final Set<String> identifiers;
198+
199+
Architecture(String... identifiers) {
200+
this.identifiers = new HashSet<>(Arrays.asList(identifiers));
201+
}
202+
203+
static Architecture of(String identifier) {
204+
for (Architecture architecture : Architecture.values()) {
205+
if (architecture.identifiers.contains(identifier)) {
206+
return architecture;
207+
}
208+
}
209+
return UNKNOWN;
210+
}
211+
212+
static Architecture current() {
213+
String property = SystemProperties.getOrDefault(OS_ARCH_PROPERTY, "").toLowerCase(ROOT);
214+
return Architecture.of(property);
215+
}
216+
}
149217
}

components/environment/src/test/java/datadog/environment/OperatingSystemTest.java

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,17 @@
11
package datadog.environment;
22

3+
import static datadog.environment.OperatingSystem.Architecture.ARM;
4+
import static datadog.environment.OperatingSystem.Architecture.ARM64;
5+
import static datadog.environment.OperatingSystem.Architecture.X64;
6+
import static datadog.environment.OperatingSystem.Architecture.X86;
7+
import static org.junit.jupiter.api.Assertions.assertEquals;
38
import static org.junit.jupiter.api.Assertions.assertFalse;
49
import static org.junit.jupiter.api.Assertions.assertTrue;
510
import static org.junit.jupiter.api.condition.OS.LINUX;
611
import static org.junit.jupiter.api.condition.OS.MAC;
712
import static org.junit.jupiter.api.condition.OS.WINDOWS;
813

14+
import datadog.environment.OperatingSystem.Type;
915
import org.junit.jupiter.api.Test;
1016
import org.junit.jupiter.api.condition.EnabledOnOs;
1117

@@ -16,6 +22,7 @@ void onLinuxOnly() {
1622
assertTrue(OperatingSystem.isLinux());
1723
assertFalse(OperatingSystem.isMacOs());
1824
assertFalse(OperatingSystem.isWindows());
25+
assertEquals(Type.LINUX, OperatingSystem.type());
1926
}
2027

2128
@Test
@@ -24,6 +31,7 @@ void onMacOsOnly() {
2431
assertFalse(OperatingSystem.isLinux());
2532
assertTrue(OperatingSystem.isMacOs());
2633
assertFalse(OperatingSystem.isWindows());
34+
assertEquals(Type.MACOS, OperatingSystem.type());
2735
}
2836

2937
@Test
@@ -32,5 +40,30 @@ void onWindowsOnly() {
3240
assertFalse(OperatingSystem.isLinux());
3341
assertFalse(OperatingSystem.isMacOs());
3442
assertTrue(OperatingSystem.isWindows());
43+
assertEquals(Type.WINDOWS, OperatingSystem.type());
44+
}
45+
46+
@Test
47+
@EnabledOnOs(architectures = {"x86_64", "amd64", "k8"})
48+
void onX64() {
49+
assertEquals(X64, OperatingSystem.architecture());
50+
}
51+
52+
@Test
53+
@EnabledOnOs(architectures = {"x86", "i386", "i486", "i586", "i686"})
54+
void onX86() {
55+
assertEquals(X86, OperatingSystem.architecture());
56+
}
57+
58+
@Test
59+
@EnabledOnOs(architectures = {"arm", "aarch32"})
60+
void onArm() {
61+
assertEquals(ARM, OperatingSystem.architecture());
62+
}
63+
64+
@Test
65+
@EnabledOnOs(architectures = {"arm64", "aarch64"})
66+
void onArm64() {
67+
assertEquals(ARM64, OperatingSystem.architecture());
3568
}
3669
}

dd-java-agent/agent-profiling/profiling-controller/src/main/java/com/datadog/profiling/controller/EnvironmentChecker.java

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
package com.datadog.profiling.controller;
22

3+
import static datadog.environment.OperatingSystem.Architecture.ARM64;
4+
35
import datadog.environment.JavaVirtualMachine;
46
import datadog.environment.OperatingSystem;
57
import datadog.environment.SystemProperties;
@@ -242,7 +244,10 @@ private static boolean extractSoFromJar(Path target, StringBuilder sb) throws Ex
242244
.filter(
243245
e ->
244246
e.getName()
245-
.contains(OperatingSystem.isAarch64() ? "/linux-arm64/" : "/linux-x64/")
247+
.contains(
248+
OperatingSystem.architecture() == ARM64
249+
? "/linux-arm64/"
250+
: "/linux-x64/")
246251
&& (!OperatingSystem.isMusl() || e.getName().contains("-musl")))
247252
.findFirst()
248253
.map(

dd-java-agent/agent-profiling/profiling-ddprof/src/main/java/com/datadog/profiling/ddprof/Arch.java

Lines changed: 0 additions & 35 deletions
This file was deleted.

dd-java-agent/agent-profiling/profiling-ddprof/src/main/java/com/datadog/profiling/ddprof/OperatingSystem.java

Lines changed: 0 additions & 33 deletions
This file was deleted.

dd-java-agent/agent-profiling/src/main/java/com/datadog/profiling/agent/CompositeController.java

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,8 @@
1111
import com.datadog.profiling.controller.ddprof.DatadogProfilerController;
1212
import com.datadog.profiling.controller.openjdk.OpenJdkController;
1313
import com.datadog.profiling.controller.oracle.OracleJdkController;
14-
import com.datadog.profiling.ddprof.Arch;
15-
import com.datadog.profiling.ddprof.OperatingSystem;
1614
import datadog.environment.JavaVirtualMachine;
15+
import datadog.environment.OperatingSystem;
1716
import datadog.environment.SystemProperties;
1817
import datadog.trace.api.Config;
1918
import datadog.trace.api.Platform;
@@ -168,8 +167,8 @@ public static Controller build(ConfigProvider provider, ControllerContext contex
168167
ProfilerFlareLogger.getInstance()
169168
.log(
170169
"JFR is not available on this platform: {}, {}",
171-
OperatingSystem.current(),
172-
Arch.current());
170+
OperatingSystem.type(),
171+
OperatingSystem.architecture());
173172
}
174173
} catch (Throwable t) {
175174
ProfilerFlareLogger.getInstance().log("Failed to load openjdk profiler", t);
@@ -186,14 +185,16 @@ public static Controller build(ConfigProvider provider, ControllerContext contex
186185
} catch (Throwable error) {
187186
Throwable rootCause = error.getCause() == null ? error : error.getCause();
188187
context.setDatadogProfilerUnavailableReason(rootCause.getMessage());
189-
OperatingSystem os = OperatingSystem.current();
190-
if (os != OperatingSystem.linux) {
188+
if (!isLinux()) {
191189
ProfilerFlareLogger.getInstance()
192190
.log("Datadog profiler only supported on Linux", rootCause);
193191
} else {
194192
ProfilerFlareLogger.getInstance()
195193
.log(
196-
"Failed to instantiate Datadog profiler on {} {}", os, Arch.current(), rootCause);
194+
"Failed to instantiate Datadog profiler on {} {}",
195+
OperatingSystem.type(),
196+
OperatingSystem.architecture(),
197+
rootCause);
197198
}
198199
}
199200
} else {

dd-trace-core/src/test/groovy/datadog/trace/api/writer/TraceStructureWriterTest.groovy

Lines changed: 24 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3,28 +3,40 @@ package datadog.trace.api.writer
33

44
import datadog.trace.common.writer.TraceStructureWriter
55
import datadog.trace.core.test.DDCoreSpecification
6+
import spock.lang.IgnoreIf
67

78
class TraceStructureWriterTest extends DDCoreSpecification {
9+
@IgnoreIf({os.windows})
810
def "parse CLI args"() {
911
when:
10-
System.setProperty("os.name", osName)
1112
def args = TraceStructureWriter.parseArgs(cli)
1213

1314
then:
1415
args.length > 0
1516
args[0] == path
1617

1718
where:
18-
osName | cli | path
19-
'Windows' | 'C:/tmp/file' | 'C:/tmp/file'
20-
'Windows' | 'C:\\tmp\\file' | 'C:\\tmp\\file'
21-
'Windows' | 'file' | 'file'
22-
'Windows' | 'C:/tmp/file:includeresource' | 'C:/tmp/file'
23-
'Windows' | 'C:\\tmp\\file:includeresource' | 'C:\\tmp\\file'
24-
'Windows' | 'file:includeresource' | 'file'
25-
'Linux' | '/var/tmp/file' | '/var/tmp/file'
26-
'Linux' | 'file' | 'file'
27-
'MacOS' | '/var/tmp/file' | '/var/tmp/file'
28-
'MacOS' | 'file' | 'file'
19+
cli | path
20+
'/var/tmp/file' | '/var/tmp/file'
21+
'file' | 'file'
22+
}
23+
24+
@IgnoreIf({!os.windows})
25+
def "parse CLI args on Windows"() {
26+
when:
27+
def args = TraceStructureWriter.parseArgs(cli)
28+
29+
then:
30+
args.length > 0
31+
args[0] == path
32+
33+
where:
34+
cli | path
35+
'C:/tmp/file' | 'C:/tmp/file'
36+
'C:\\tmp\\file' | 'C:\\tmp\\file'
37+
'file' | 'file'
38+
'C:/tmp/file:includeresource' | 'C:/tmp/file'
39+
'C:\\tmp\\file:includeresource' | 'C:\\tmp\\file'
40+
'file:includeresource' | 'file'
2941
}
3042
}

0 commit comments

Comments
 (0)