Skip to content

Commit cbdc404

Browse files
sarahchen6mcculls
andauthored
Add JDK built-in support for UDS on Java 16+ (#8314)
* Use the JDK's built-in support for Unix Domain Sockets on Java 16+ * First draft of timeout test. * Add server to test. * Fix build.gradle file. * Add debugging statements. * Second draft of timeout test. * Update getInputStream to use a selector. * Clean code. * Adjust dd-java-agent build.gradle. * Revert dd-java-agent build.gradle change * Revert another build.gradle change. * Try specifying setSrcDirs. * Try changing compatibility version. * Revert previous two changes. * Avoid implementation dependency for Java17. * Make gradle dependency more specific and add testImplementation to socket-utils. * Add synchronization to ensure that server starts before client connects. * Try this... * Add print statements. * Add catch statement. * Refactor getInputStream and getOutputStream. * Address PR comments. * Add test for when timeout is 0. * Add config option. --------- Co-authored-by: Stuart McCulloch <[email protected]>
1 parent eb4c52e commit cbdc404

File tree

8 files changed

+417
-5
lines changed

8 files changed

+417
-5
lines changed

dd-trace-api/src/main/java/datadog/trace/api/config/GeneralConfig.java

+1
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@ public final class GeneralConfig {
9494
public static final String AGENTLESS_LOG_SUBMISSION_LEVEL = "agentless.log.submission.level";
9595
public static final String AGENTLESS_LOG_SUBMISSION_URL = "agentless.log.submission.url";
9696
public static final String APM_TRACING_ENABLED = "apm.tracing.enabled";
97+
public static final String JDK_SOCKET_ENABLED = "jdk.socket.enabled";
9798

9899
private GeneralConfig() {}
99100
}

gradle/java_no_deps.gradle

+8-2
Original file line numberDiff line numberDiff line change
@@ -59,9 +59,15 @@ if (project.hasProperty('minJavaVersionForTests') && project.getProperty('minJav
5959
targetCompatibility = version
6060
}
6161

62+
// "socket-utils" is only set to compileOnly because the implementation dependency incorrectly adds Java17 classes to all jar prefixes.
63+
// This causes the AgentJarIndex to search for other non-Java17 classes in the wrong prefix location and fail to resolve class names.
6264
dependencies {
63-
compileOnly files(project.sourceSets."main_$name".compileClasspath)
64-
implementation files(project.sourceSets."main_$name".output)
65+
if ("${project.projectDir}".endsWith("socket-utils")) {
66+
compileOnly files(project.sourceSets."main_$name".output)
67+
} else {
68+
compileOnly files(project.sourceSets."main_$name".compileClasspath)
69+
implementation files(project.sourceSets."main_$name".output)
70+
}
6571
}
6672

6773
jar {

internal-api/src/main/java/datadog/trace/api/Config.java

+10
Original file line numberDiff line numberDiff line change
@@ -563,6 +563,8 @@ public static String getHostName() {
563563
private final boolean apmTracingEnabled;
564564
private final Set<String> experimentalFeaturesEnabled;
565565

566+
private final boolean jdkSocketEnabled;
567+
566568
// Read order: System Properties -> Env Variables, [-> properties file], [-> default value]
567569
private Config() {
568570
this(ConfigProvider.createDefault());
@@ -1959,6 +1961,8 @@ PROFILING_DATADOG_PROFILER_ENABLED, isDatadogProfilerSafeInCurrentEnvironment())
19591961

19601962
this.apmTracingEnabled = configProvider.getBoolean(GeneralConfig.APM_TRACING_ENABLED, true);
19611963

1964+
this.jdkSocketEnabled = configProvider.getBoolean(JDK_SOCKET_ENABLED, true);
1965+
19621966
log.debug("New instance: {}", this);
19631967
}
19641968

@@ -3537,6 +3541,10 @@ public boolean isApmTracingEnabled() {
35373541
return apmTracingEnabled;
35383542
}
35393543

3544+
public boolean isJdkSocketEnabled() {
3545+
return jdkSocketEnabled;
3546+
}
3547+
35403548
/** @return A map of tags to be applied only to the local application root span. */
35413549
public Map<String, Object> getLocalRootSpanTags() {
35423550
final Map<String, String> runtimeTags = getRuntimeTags();
@@ -4784,6 +4792,8 @@ public String toString() {
47844792
+ dataJobsCommandPattern
47854793
+ ", apmTracingEnabled="
47864794
+ apmTracingEnabled
4795+
+ ", jdkSocketEnabled="
4796+
+ jdkSocketEnabled
47874797
+ ", cloudRequestPayloadTagging="
47884798
+ cloudRequestPayloadTagging
47894799
+ ", cloudResponsePayloadTagging="

internal-api/src/test/groovy/datadog/trace/api/ConfigTest.groovy

+3
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ import static datadog.trace.api.config.GeneralConfig.GLOBAL_TAGS
5151
import static datadog.trace.api.config.GeneralConfig.HEALTH_METRICS_ENABLED
5252
import static datadog.trace.api.config.GeneralConfig.HEALTH_METRICS_STATSD_HOST
5353
import static datadog.trace.api.config.GeneralConfig.HEALTH_METRICS_STATSD_PORT
54+
import static datadog.trace.api.config.GeneralConfig.JDK_SOCKET_ENABLED
5455
import static datadog.trace.api.config.GeneralConfig.PERF_METRICS_ENABLED
5556
import static datadog.trace.api.config.GeneralConfig.SERVICE_NAME
5657
import static datadog.trace.api.config.GeneralConfig.SITE
@@ -261,6 +262,7 @@ class ConfigTest extends DDSpecification {
261262
prop.setProperty(DYNAMIC_INSTRUMENTATION_EXCLUDE_FILES, "exclude file")
262263
prop.setProperty(EXCEPTION_REPLAY_ENABLED, "true")
263264
prop.setProperty(TRACE_X_DATADOG_TAGS_MAX_LENGTH, "128")
265+
prop.setProperty(JDK_SOCKET_ENABLED, "false")
264266

265267
when:
266268
Config config = Config.get(prop)
@@ -354,6 +356,7 @@ class ConfigTest extends DDSpecification {
354356
config.dynamicInstrumentationInstrumentTheWorld == true
355357
config.dynamicInstrumentationExcludeFiles == "exclude file"
356358
config.debuggerExceptionEnabled == true
359+
config.jdkSocketEnabled == false
357360

358361
config.xDatadogTagsMaxLength == 128
359362
}

utils/socket-utils/build.gradle

+24-1
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,31 @@
1+
ext {
2+
minJavaVersionForTests = JavaVersion.VERSION_17
3+
}
4+
15
apply from: "$rootDir/gradle/java.gradle"
6+
apply plugin: "idea"
7+
8+
[compileMain_java17Java, compileTestJava].each {
9+
it.configure {
10+
setJavaVersion(it, 17)
11+
sourceCompatibility = JavaVersion.VERSION_1_8
12+
targetCompatibility = JavaVersion.VERSION_1_8
13+
}
14+
}
215

316
dependencies {
417
implementation libs.slf4j
518
implementation project(':internal-api')
19+
implementation libs.jnr.unixsocket
20+
testImplementation files(sourceSets.main_java17.output)
21+
}
22+
23+
forbiddenApisMain_java17 {
24+
failOnMissingClasses = false
25+
}
626

7-
implementation group: 'com.github.jnr', name: 'jnr-unixsocket', version: libs.versions.jnr.unixsocket.get()
27+
idea {
28+
module {
29+
jdkName = '17'
30+
}
831
}

utils/socket-utils/src/main/java/datadog/common/socket/UnixDomainSocketFactory.java

+11-2
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import static java.util.concurrent.TimeUnit.MINUTES;
44

55
import datadog.trace.api.Config;
6+
import datadog.trace.api.Platform;
67
import datadog.trace.relocate.api.RatelimitedLogger;
78
import java.io.File;
89
import java.io.IOException;
@@ -24,6 +25,8 @@
2425
public final class UnixDomainSocketFactory extends SocketFactory {
2526
private static final Logger log = LoggerFactory.getLogger(UnixDomainSocketFactory.class);
2627

28+
private static final boolean JDK_SUPPORTS_UDS = Platform.isJavaVersionAtLeast(16);
29+
2730
private final RatelimitedLogger rlLog = new RatelimitedLogger(log, 5, MINUTES);
2831

2932
private final File path;
@@ -35,8 +38,14 @@ public UnixDomainSocketFactory(final File path) {
3538
@Override
3639
public Socket createSocket() throws IOException {
3740
try {
38-
final UnixSocketChannel channel = UnixSocketChannel.open();
39-
return new TunnelingUnixSocket(path, channel);
41+
if (JDK_SUPPORTS_UDS && Config.get().isJdkSocketEnabled()) {
42+
try {
43+
return new TunnelingJdkSocket(path.toPath());
44+
} catch (Throwable ignore) {
45+
// fall back to jnr-unixsocket library
46+
}
47+
}
48+
return new TunnelingUnixSocket(path, UnixSocketChannel.open());
4049
} catch (Throwable e) {
4150
if (Config.get().isAgentConfiguredUsingDefault()) {
4251
// fall back to port if we previously auto-discovered this socket file

0 commit comments

Comments
 (0)