From 55c1a1643d52ee58494f3255a71743f227143b8b Mon Sep 17 00:00:00 2001 From: Paul Fournillon Date: Sun, 9 Aug 2026 14:00:31 +0200 Subject: [PATCH] feat: add support for native_socket ddprof config --- .../profiling/ddprof/DatadogProfiler.java | 14 +++++++ .../ddprof/DatadogProfilerConfig.java | 25 +++++++++++ .../profiling/ddprof/DatadogProfilerTest.java | 42 +++++++++++++++++++ .../profiling/utils/ProfilingMode.java | 3 +- .../src/test/resources/ffe-system-test-data | 1 - .../trace/api/config/ProfilingConfig.java | 6 +++ metadata/supported-configurations.json | 16 +++++++ 7 files changed, 105 insertions(+), 2 deletions(-) delete mode 160000 dd-smoke-tests/openfeature/src/test/resources/ffe-system-test-data diff --git a/dd-java-agent/agent-profiling/profiling-ddprof/src/main/java/com/datadog/profiling/ddprof/DatadogProfiler.java b/dd-java-agent/agent-profiling/profiling-ddprof/src/main/java/com/datadog/profiling/ddprof/DatadogProfiler.java index 0d68e2e0c3f..897b12d1334 100644 --- a/dd-java-agent/agent-profiling/profiling-ddprof/src/main/java/com/datadog/profiling/ddprof/DatadogProfiler.java +++ b/dd-java-agent/agent-profiling/profiling-ddprof/src/main/java/com/datadog/profiling/ddprof/DatadogProfiler.java @@ -8,6 +8,7 @@ import static com.datadog.profiling.ddprof.DatadogProfilerConfig.getLiveHeapSamplePercent; import static com.datadog.profiling.ddprof.DatadogProfilerConfig.getLogLevel; import static com.datadog.profiling.ddprof.DatadogProfilerConfig.getNativeMemoryInterval; +import static com.datadog.profiling.ddprof.DatadogProfilerConfig.getNativeSocketInterval; import static com.datadog.profiling.ddprof.DatadogProfilerConfig.getSafeMode; import static com.datadog.profiling.ddprof.DatadogProfilerConfig.getSchedulingEvent; import static com.datadog.profiling.ddprof.DatadogProfilerConfig.getSchedulingEventInterval; @@ -20,6 +21,7 @@ import static com.datadog.profiling.ddprof.DatadogProfilerConfig.isLiveHeapSizeTrackingEnabled; import static com.datadog.profiling.ddprof.DatadogProfilerConfig.isMemoryLeakProfilingEnabled; import static com.datadog.profiling.ddprof.DatadogProfilerConfig.isNativeMemoryProfilingEnabled; +import static com.datadog.profiling.ddprof.DatadogProfilerConfig.isNativeSocketProfilingEnabled; import static com.datadog.profiling.ddprof.DatadogProfilerConfig.isResourceNameContextAttributeEnabled; import static com.datadog.profiling.ddprof.DatadogProfilerConfig.isSpanNameContextAttributeEnabled; import static com.datadog.profiling.ddprof.DatadogProfilerConfig.isTrackingGenerations; @@ -29,6 +31,7 @@ import static com.datadog.profiling.utils.ProfilingMode.CPU; import static com.datadog.profiling.utils.ProfilingMode.MEMLEAK; import static com.datadog.profiling.utils.ProfilingMode.NATIVEMEM; +import static com.datadog.profiling.utils.ProfilingMode.NATIVESOCKET; import static com.datadog.profiling.utils.ProfilingMode.WALL; import static datadog.trace.api.config.ProfilingConfig.PROFILING_DETAILED_DEBUG_LOGGING; import static datadog.trace.api.config.ProfilingConfig.PROFILING_DETAILED_DEBUG_LOGGING_DEFAULT; @@ -243,6 +246,9 @@ private DatadogProfiler(ConfigProvider configProvider) { if (isNativeMemoryProfilingEnabled(configProvider)) { profilingModes.add(NATIVEMEM); } + if (isNativeSocketProfilingEnabled(configProvider)) { + profilingModes.add(NATIVESOCKET); + } Set contextAttributes = getContextAttributes(configProvider); this.orderedContextAttributes = getOrderedContextAttributes(contextAttributes, configProvider); this.contextSetter = new ContextSetter(profiler, orderedContextAttributes); @@ -469,6 +475,14 @@ String cmdStartProfiling(Path file) throws IllegalStateException { // native memory (malloc) profiling is enabled cmd.append(",nativemem=").append(getNativeMemoryInterval(configProvider)); } + if (profilingModes.contains(NATIVESOCKET)) { + // native socket I/O profiling is enabled + String interval = getNativeSocketInterval(configProvider); + cmd.append(",natsock"); + if (interval != null && !interval.isEmpty()) { + cmd.append('=').append(interval); + } + } String cmdString = cmd.toString(); log.debug("Datadog profiler command line: {}", cmdString); return cmdString; diff --git a/dd-java-agent/agent-profiling/profiling-ddprof/src/main/java/com/datadog/profiling/ddprof/DatadogProfilerConfig.java b/dd-java-agent/agent-profiling/profiling-ddprof/src/main/java/com/datadog/profiling/ddprof/DatadogProfilerConfig.java index c95db897fb3..b54b069fe55 100644 --- a/dd-java-agent/agent-profiling/profiling-ddprof/src/main/java/com/datadog/profiling/ddprof/DatadogProfilerConfig.java +++ b/dd-java-agent/agent-profiling/profiling-ddprof/src/main/java/com/datadog/profiling/ddprof/DatadogProfilerConfig.java @@ -37,6 +37,9 @@ import static datadog.trace.api.config.ProfilingConfig.PROFILING_DATADOG_PROFILER_NATIVEMEM_ENABLED_DEFAULT; import static datadog.trace.api.config.ProfilingConfig.PROFILING_DATADOG_PROFILER_NATIVEMEM_INTERVAL; import static datadog.trace.api.config.ProfilingConfig.PROFILING_DATADOG_PROFILER_NATIVEMEM_INTERVAL_DEFAULT; +import static datadog.trace.api.config.ProfilingConfig.PROFILING_DATADOG_PROFILER_NATIVESOCKET_ENABLED; +import static datadog.trace.api.config.ProfilingConfig.PROFILING_DATADOG_PROFILER_NATIVESOCKET_ENABLED_DEFAULT; +import static datadog.trace.api.config.ProfilingConfig.PROFILING_DATADOG_PROFILER_NATIVESOCKET_INTERVAL; import static datadog.trace.api.config.ProfilingConfig.PROFILING_DATADOG_PROFILER_SAFEMODE; import static datadog.trace.api.config.ProfilingConfig.PROFILING_DATADOG_PROFILER_SAFEMODE_DEFAULT; import static datadog.trace.api.config.ProfilingConfig.PROFILING_DATADOG_PROFILER_SCHEDULING_EVENT; @@ -318,6 +321,28 @@ public static int getNativeMemoryInterval() { return getNativeMemoryInterval(ConfigProvider.getInstance()); } + public static boolean isNativeSocketProfilingEnabled(ConfigProvider configProvider) { + // natsock never shipped under the legacy '.async.' naming, so it has no async-translated + // form to fall back to — call the provider directly instead of the ddprof->async helper. + return configProvider.getBoolean( + PROFILING_DATADOG_PROFILER_NATIVESOCKET_ENABLED, + PROFILING_DATADOG_PROFILER_NATIVESOCKET_ENABLED_DEFAULT); + } + + public static boolean isNativeSocketProfilingEnabled() { + return isNativeSocketProfilingEnabled(ConfigProvider.getInstance()); + } + + public static String getNativeSocketInterval(ConfigProvider configProvider) { + // natsock never shipped under the legacy '.async.' naming, so it has no async-translated + // form to fall back to — call the provider directly instead of the ddprof->async helper. + return configProvider.getString(PROFILING_DATADOG_PROFILER_NATIVESOCKET_INTERVAL); + } + + public static String getNativeSocketInterval() { + return getNativeSocketInterval(ConfigProvider.getInstance()); + } + public static int getStackDepth(ConfigProvider configProvider) { return getInteger( configProvider, diff --git a/dd-java-agent/agent-profiling/profiling-ddprof/src/test/java/com/datadog/profiling/ddprof/DatadogProfilerTest.java b/dd-java-agent/agent-profiling/profiling-ddprof/src/test/java/com/datadog/profiling/ddprof/DatadogProfilerTest.java index 008b70b1e66..c09e6ce8fb9 100644 --- a/dd-java-agent/agent-profiling/profiling-ddprof/src/test/java/com/datadog/profiling/ddprof/DatadogProfilerTest.java +++ b/dd-java-agent/agent-profiling/profiling-ddprof/src/test/java/com/datadog/profiling/ddprof/DatadogProfilerTest.java @@ -147,6 +147,48 @@ void testStartCmdNativeMemEnabled() throws Exception { assertTrue(startCmd(profiler).contains(",nativemem=131072")); } + @Test + void testStartCmdNativeSocketDisabledByDefault() throws Exception { + assertDoesNotThrow( + () -> DdprofLibraryLoader.jvmAccess().getReasonNotLoaded(), "Profiler not available"); + + DatadogProfiler profiler = DatadogProfiler.newInstance(ConfigProvider.getInstance()); + assertFalse(profiler.enabledModes().contains(ProfilingMode.NATIVESOCKET)); + + assertFalse(startCmd(profiler).contains(",natsock")); + } + + @Test + void testStartCmdNativeSocketEnabledWithoutInterval() throws Exception { + assertDoesNotThrow( + () -> DdprofLibraryLoader.jvmAccess().getReasonNotLoaded(), "Profiler not available"); + + Properties props = new Properties(); + props.put(ProfilingConfig.PROFILING_DATADOG_PROFILER_NATIVESOCKET_ENABLED, "true"); + DatadogProfiler profiler = + DatadogProfiler.newInstance(ConfigProvider.withPropertiesOverride(props)); + assertTrue(profiler.enabledModes().contains(ProfilingMode.NATIVESOCKET)); + + String cmd = startCmd(profiler); + assertTrue(cmd.contains(",natsock")); + assertFalse(cmd.contains(",natsock=")); + } + + @Test + void testStartCmdNativeSocketEnabledWithInterval() throws Exception { + assertDoesNotThrow( + () -> DdprofLibraryLoader.jvmAccess().getReasonNotLoaded(), "Profiler not available"); + + Properties props = new Properties(); + props.put(ProfilingConfig.PROFILING_DATADOG_PROFILER_NATIVESOCKET_ENABLED, "true"); + props.put(ProfilingConfig.PROFILING_DATADOG_PROFILER_NATIVESOCKET_INTERVAL, "100us"); + DatadogProfiler profiler = + DatadogProfiler.newInstance(ConfigProvider.withPropertiesOverride(props)); + assertTrue(profiler.enabledModes().contains(ProfilingMode.NATIVESOCKET)); + + assertTrue(startCmd(profiler).contains(",natsock=100us")); + } + private static String startCmd(DatadogProfiler profiler) throws Exception { Path targetFile = Files.createTempFile(Paths.get("/tmp"), "target_", ".jfr"); return profiler.cmdStartProfiling(targetFile); diff --git a/dd-java-agent/agent-profiling/profiling-utils/src/main/java/com/datadog/profiling/utils/ProfilingMode.java b/dd-java-agent/agent-profiling/profiling-utils/src/main/java/com/datadog/profiling/utils/ProfilingMode.java index e313c064445..114ab8a6124 100644 --- a/dd-java-agent/agent-profiling/profiling-utils/src/main/java/com/datadog/profiling/utils/ProfilingMode.java +++ b/dd-java-agent/agent-profiling/profiling-utils/src/main/java/com/datadog/profiling/utils/ProfilingMode.java @@ -8,7 +8,8 @@ public enum ProfilingMode { WALL(1 << 1), ALLOCATION(1 << 2), MEMLEAK(1 << 3), - NATIVEMEM(1 << 4); + NATIVEMEM(1 << 4), + NATIVESOCKET(1 << 5); public final int bitmask; diff --git a/dd-smoke-tests/openfeature/src/test/resources/ffe-system-test-data b/dd-smoke-tests/openfeature/src/test/resources/ffe-system-test-data deleted file mode 160000 index b42c4a104ea..00000000000 --- a/dd-smoke-tests/openfeature/src/test/resources/ffe-system-test-data +++ /dev/null @@ -1 +0,0 @@ -Subproject commit b42c4a104ea70695c8fc3516780951f7434b7906 diff --git a/dd-trace-api/src/main/java/datadog/trace/api/config/ProfilingConfig.java b/dd-trace-api/src/main/java/datadog/trace/api/config/ProfilingConfig.java index bf5f7a552e9..37dc6c3c500 100644 --- a/dd-trace-api/src/main/java/datadog/trace/api/config/ProfilingConfig.java +++ b/dd-trace-api/src/main/java/datadog/trace/api/config/ProfilingConfig.java @@ -187,6 +187,12 @@ public final class ProfilingConfig { "profiling.experimental.ddprof.nativemem.interval"; public static final int PROFILING_DATADOG_PROFILER_NATIVEMEM_INTERVAL_DEFAULT = 512 * 1024; + public static final String PROFILING_DATADOG_PROFILER_NATIVESOCKET_ENABLED = + "profiling.experimental.ddprof.nativesocket.enabled"; + public static final boolean PROFILING_DATADOG_PROFILER_NATIVESOCKET_ENABLED_DEFAULT = false; + public static final String PROFILING_DATADOG_PROFILER_NATIVESOCKET_INTERVAL = + "profiling.experimental.ddprof.nativesocket.interval"; + public static final String PROFILING_ENDPOINT_COLLECTION_ENABLED = "profiling.endpoint.collection.enabled"; public static final boolean PROFILING_ENDPOINT_COLLECTION_ENABLED_DEFAULT = true; diff --git a/metadata/supported-configurations.json b/metadata/supported-configurations.json index aaad660aae9..c60de4eb738 100644 --- a/metadata/supported-configurations.json +++ b/metadata/supported-configurations.json @@ -3249,6 +3249,22 @@ "aliases": [] } ], + "DD_PROFILING_EXPERIMENTAL_DDPROF_NATIVESOCKET_ENABLED": [ + { + "version": "A", + "type": "boolean", + "default": "false", + "aliases": [] + } + ], + "DD_PROFILING_EXPERIMENTAL_DDPROF_NATIVESOCKET_INTERVAL": [ + { + "version": "A", + "type": "string", + "default": null, + "aliases": [] + } + ], "DD_PROFILING_EXPERIMENTAL_DDPROF_SCHEDULING_EVENT": [ { "version": "A",