diff --git a/dd-java-agent/agent-profiling/profiling-controller-openjdk/src/main/java/com/datadog/profiling/controller/openjdk/OpenJdkController.java b/dd-java-agent/agent-profiling/profiling-controller-openjdk/src/main/java/com/datadog/profiling/controller/openjdk/OpenJdkController.java index e5a625db7a7..fe2292b9cfb 100644 --- a/dd-java-agent/agent-profiling/profiling-controller-openjdk/src/main/java/com/datadog/profiling/controller/openjdk/OpenJdkController.java +++ b/dd-java-agent/agent-profiling/profiling-controller-openjdk/src/main/java/com/datadog/profiling/controller/openjdk/OpenJdkController.java @@ -17,14 +17,24 @@ import static com.datadog.profiling.controller.ProfilingSupport.*; import static datadog.environment.JavaVirtualMachine.isJavaVersionAtLeast; +import static datadog.trace.api.config.ProfilingConfig.PROFILING_CPU_ENABLED; +import static datadog.trace.api.config.ProfilingConfig.PROFILING_CPU_ENABLED_DEFAULT; +import static datadog.trace.api.config.ProfilingConfig.PROFILING_EXCEPTION_ENABLED; +import static datadog.trace.api.config.ProfilingConfig.PROFILING_EXCEPTION_ENABLED_DEFAULT; import static datadog.trace.api.config.ProfilingConfig.PROFILING_HEAP_HISTOGRAM_ENABLED; import static datadog.trace.api.config.ProfilingConfig.PROFILING_HEAP_HISTOGRAM_ENABLED_DEFAULT; import static datadog.trace.api.config.ProfilingConfig.PROFILING_HEAP_HISTOGRAM_MODE; import static datadog.trace.api.config.ProfilingConfig.PROFILING_HEAP_HISTOGRAM_MODE_DEFAULT; +import static datadog.trace.api.config.ProfilingConfig.PROFILING_IO_ENABLED; +import static datadog.trace.api.config.ProfilingConfig.PROFILING_IO_ENABLED_DEFAULT; +import static datadog.trace.api.config.ProfilingConfig.PROFILING_LOCK_ENABLED; +import static datadog.trace.api.config.ProfilingConfig.PROFILING_LOCK_ENABLED_DEFAULT; import static datadog.trace.api.config.ProfilingConfig.PROFILING_QUEUEING_TIME_ENABLED; import static datadog.trace.api.config.ProfilingConfig.PROFILING_QUEUEING_TIME_ENABLED_DEFAULT; import static datadog.trace.api.config.ProfilingConfig.PROFILING_QUEUEING_TIME_THRESHOLD_MILLIS; import static datadog.trace.api.config.ProfilingConfig.PROFILING_QUEUEING_TIME_THRESHOLD_MILLIS_DEFAULT; +import static datadog.trace.api.config.ProfilingConfig.PROFILING_THREAD_ENABLED; +import static datadog.trace.api.config.ProfilingConfig.PROFILING_THREAD_ENABLED_DEFAULT; import static datadog.trace.api.config.ProfilingConfig.PROFILING_ULTRA_MINIMAL; import com.datadog.profiling.controller.ConfigurationException; @@ -264,6 +274,50 @@ ProfilingConfig.PROFILING_ALLOCATION_ENABLED, isObjectAllocationSampleAvailable( "Aggregated smaps collection is disabled in the config"); } + // Feature gates — unified profiling.*.enabled keys. + // These gates are evaluated at recording creation time only; profiling does not use Remote + // Config, so events disabled here remain disabled for the lifetime of the recording. + + if (!configProvider.getBoolean(PROFILING_CPU_ENABLED, PROFILING_CPU_ENABLED_DEFAULT)) { + disableEvent(recordingSettings, "jdk.ExecutionSample", "CPU profiling is disabled"); + disableEvent(recordingSettings, "jdk.NativeMethodSample", "CPU profiling is disabled"); + disableEvent(recordingSettings, "jdk.CPUTimeSample", "CPU profiling is disabled"); + disableEvent(recordingSettings, "jdk.CPUTimeSamplesLost", "CPU profiling is disabled"); + } + + // jdk.JavaMonitorWait, jdk.ThreadPark, and jdk.ThreadSleep are intentionally NOT gated by + // PROFILING_WALL_ENABLED: they serve purposes beyond wall-clock profile construction + // (timeline blocking events, queueing time) and must remain enabled independently. + + if (!configProvider.getBoolean( + PROFILING_EXCEPTION_ENABLED, PROFILING_EXCEPTION_ENABLED_DEFAULT)) { + disableEvent(recordingSettings, "datadog.ExceptionSample", "exception profiling is disabled"); + disableEvent(recordingSettings, "datadog.ExceptionCount", "exception profiling is disabled"); + } + + if (!configProvider.getBoolean(PROFILING_IO_ENABLED, PROFILING_IO_ENABLED_DEFAULT)) { + disableEvent(recordingSettings, "jdk.FileRead", "I/O profiling is disabled"); + disableEvent(recordingSettings, "jdk.FileWrite", "I/O profiling is disabled"); + disableEvent(recordingSettings, "jdk.FileForce", "I/O profiling is disabled"); + disableEvent(recordingSettings, "jdk.SocketRead", "I/O profiling is disabled"); + disableEvent(recordingSettings, "jdk.SocketWrite", "I/O profiling is disabled"); + } + + if (!configProvider.getBoolean(PROFILING_LOCK_ENABLED, PROFILING_LOCK_ENABLED_DEFAULT)) { + disableEvent(recordingSettings, "jdk.JavaMonitorEnter", "lock profiling is disabled"); + // BiasedLock events are no-ops on JDK 18+ (biased locking removed via JEP 374); disabling + // them here is harmless on modern JDKs. + disableEvent(recordingSettings, "jdk.BiasedLockRevocation", "lock profiling is disabled"); + disableEvent(recordingSettings, "jdk.BiasedLockSelfRevocation", "lock profiling is disabled"); + disableEvent( + recordingSettings, "jdk.BiasedLockClassRevocation", "lock profiling is disabled"); + } + + if (!configProvider.getBoolean(PROFILING_THREAD_ENABLED, PROFILING_THREAD_ENABLED_DEFAULT)) { + disableEvent(recordingSettings, "jdk.ThreadStart", "thread profiling is disabled"); + disableEvent(recordingSettings, "jdk.ThreadEnd", "thread profiling is disabled"); + } + // Warn users for expensive events if (!isOldObjectSampleAvailable() && isEventEnabled(recordingSettings, "jdk.OldObjectSample")) { diff --git a/dd-java-agent/agent-profiling/profiling-controller-openjdk/src/test/java/com/datadog/profiling/controller/openjdk/OpenJdkControllerTest.java b/dd-java-agent/agent-profiling/profiling-controller-openjdk/src/test/java/com/datadog/profiling/controller/openjdk/OpenJdkControllerTest.java index ef853d07b9a..544b2011b46 100644 --- a/dd-java-agent/agent-profiling/profiling-controller-openjdk/src/test/java/com/datadog/profiling/controller/openjdk/OpenJdkControllerTest.java +++ b/dd-java-agent/agent-profiling/profiling-controller-openjdk/src/test/java/com/datadog/profiling/controller/openjdk/OpenJdkControllerTest.java @@ -6,9 +6,15 @@ import static datadog.trace.api.config.ProfilingConfig.PROFILING_ALLOCATION_ENABLED; import static datadog.trace.api.config.ProfilingConfig.PROFILING_AUXILIARY_TYPE; import static datadog.trace.api.config.ProfilingConfig.PROFILING_AUXILIARY_TYPE_DEFAULT; +import static datadog.trace.api.config.ProfilingConfig.PROFILING_CPU_ENABLED; import static datadog.trace.api.config.ProfilingConfig.PROFILING_DATADOG_PROFILER_ENABLED; +import static datadog.trace.api.config.ProfilingConfig.PROFILING_EXCEPTION_ENABLED; import static datadog.trace.api.config.ProfilingConfig.PROFILING_HEAP_ENABLED; +import static datadog.trace.api.config.ProfilingConfig.PROFILING_IO_ENABLED; +import static datadog.trace.api.config.ProfilingConfig.PROFILING_LOCK_ENABLED; import static datadog.trace.api.config.ProfilingConfig.PROFILING_TEMPLATE_OVERRIDE_FILE; +import static datadog.trace.api.config.ProfilingConfig.PROFILING_THREAD_ENABLED; +import static datadog.trace.api.config.ProfilingConfig.PROFILING_WALL_ENABLED; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertTrue; @@ -276,6 +282,123 @@ public void testUnifiedFlagDisabledTurnsOffOldObjectSample() throws Exception { } } + @Test + public void testCpuGateDisablesCpuEvents() throws Exception { + Properties props = getConfigProperties(); + props.put(PROFILING_CPU_ENABLED, "false"); + + ConfigProvider configProvider = ConfigProvider.withPropertiesOverride(props); + OpenJdkController controller = new OpenJdkController(configProvider); + try (final Recording recording = + ((OpenJdkRecordingData) + controller.createRecording(TEST_NAME, new ControllerContext().snapshot()).stop()) + .getRecording()) { + assertFalse( + Boolean.parseBoolean(recording.getSettings().get("jdk.ExecutionSample#enabled")), + "ExecutionSample must be disabled when CPU profiling is disabled"); + } + } + + @Test + public void testExceptionGateDisablesExceptionEvents() throws Exception { + Properties props = getConfigProperties(); + props.put(PROFILING_EXCEPTION_ENABLED, "false"); + + ConfigProvider configProvider = ConfigProvider.withPropertiesOverride(props); + OpenJdkController controller = new OpenJdkController(configProvider); + try (final Recording recording = + ((OpenJdkRecordingData) + controller.createRecording(TEST_NAME, new ControllerContext().snapshot()).stop()) + .getRecording()) { + assertFalse( + Boolean.parseBoolean(recording.getSettings().get("datadog.ExceptionSample#enabled")), + "ExceptionSample must be disabled when exception profiling is disabled"); + assertFalse( + Boolean.parseBoolean(recording.getSettings().get("datadog.ExceptionCount#enabled")), + "ExceptionCount must be disabled when exception profiling is disabled"); + } + } + + @Test + public void testIoGateDisablesIoEvents() throws Exception { + Properties props = getConfigProperties(); + props.put(PROFILING_IO_ENABLED, "false"); + + ConfigProvider configProvider = ConfigProvider.withPropertiesOverride(props); + OpenJdkController controller = new OpenJdkController(configProvider); + try (final Recording recording = + ((OpenJdkRecordingData) + controller.createRecording(TEST_NAME, new ControllerContext().snapshot()).stop()) + .getRecording()) { + assertFalse( + Boolean.parseBoolean(recording.getSettings().get("jdk.FileRead#enabled")), + "FileRead must be disabled when I/O profiling is disabled"); + assertFalse( + Boolean.parseBoolean(recording.getSettings().get("jdk.SocketRead#enabled")), + "SocketRead must be disabled when I/O profiling is disabled"); + } + } + + @Test + public void testLockGateDisablesLockEvents() throws Exception { + Properties props = getConfigProperties(); + props.put(PROFILING_LOCK_ENABLED, "false"); + + ConfigProvider configProvider = ConfigProvider.withPropertiesOverride(props); + OpenJdkController controller = new OpenJdkController(configProvider); + try (final Recording recording = + ((OpenJdkRecordingData) + controller.createRecording(TEST_NAME, new ControllerContext().snapshot()).stop()) + .getRecording()) { + assertFalse( + Boolean.parseBoolean(recording.getSettings().get("jdk.JavaMonitorEnter#enabled")), + "JavaMonitorEnter must be disabled when lock profiling is disabled"); + } + } + + @Test + public void testThreadGateDisablesThreadEvents() throws Exception { + Properties props = getConfigProperties(); + props.put(PROFILING_THREAD_ENABLED, "false"); + + ConfigProvider configProvider = ConfigProvider.withPropertiesOverride(props); + OpenJdkController controller = new OpenJdkController(configProvider); + try (final Recording recording = + ((OpenJdkRecordingData) + controller.createRecording(TEST_NAME, new ControllerContext().snapshot()).stop()) + .getRecording()) { + assertFalse( + Boolean.parseBoolean(recording.getSettings().get("jdk.ThreadStart#enabled")), + "ThreadStart must be disabled when thread profiling is disabled"); + assertFalse( + Boolean.parseBoolean(recording.getSettings().get("jdk.ThreadEnd#enabled")), + "ThreadEnd must be disabled when thread profiling is disabled"); + } + } + + @Test + public void testWallGateDoesNotDisableTimelineEvents() throws Exception { + Properties props = getConfigProperties(); + props.put(PROFILING_WALL_ENABLED, "false"); + + ConfigProvider configProvider = ConfigProvider.withPropertiesOverride(props); + OpenJdkController controller = new OpenJdkController(configProvider); + try (final Recording recording = + ((OpenJdkRecordingData) + controller.createRecording(TEST_NAME, new ControllerContext().snapshot()).stop()) + .getRecording()) { + // JavaMonitorWait and ThreadPark serve timeline purposes beyond wall-clock profiling and must + // NOT be disabled when only wall profiling is disabled. (ThreadSleep is disabled by the + // dd.jfp template by default and is therefore not checked here.) + assertTrue( + Boolean.parseBoolean(recording.getSettings().get("jdk.JavaMonitorWait#enabled")), + "JavaMonitorWait must remain enabled when only wall profiling is disabled"); + assertTrue( + Boolean.parseBoolean(recording.getSettings().get("jdk.ThreadPark#enabled")), + "ThreadPark must remain enabled when only wall profiling is disabled"); + } + } + private static Properties getConfigProperties() { Properties props = new Properties(); // make sure the async profiler is not force-enabled diff --git a/dd-java-agent/agent-profiling/profiling-controller/src/main/java/com/datadog/profiling/controller/ProfilerFlareReporter.java b/dd-java-agent/agent-profiling/profiling-controller/src/main/java/com/datadog/profiling/controller/ProfilerFlareReporter.java index 95f538a715c..3fbb13a1965 100644 --- a/dd-java-agent/agent-profiling/profiling-controller/src/main/java/com/datadog/profiling/controller/ProfilerFlareReporter.java +++ b/dd-java-agent/agent-profiling/profiling-controller/src/main/java/com/datadog/profiling/controller/ProfilerFlareReporter.java @@ -136,6 +136,55 @@ private String getProfilerConfig() { .append(proxyPassword != null ? "[REDACTED]" : null) .append(" (default: null)\n"); + sb.append("\n=== Feature Gates ===\n"); + appendConfig( + sb, + "CPU Profiling Enabled", + configProvider.getBoolean( + ProfilingConfig.PROFILING_CPU_ENABLED, ProfilingConfig.PROFILING_CPU_ENABLED_DEFAULT), + ProfilingConfig.PROFILING_CPU_ENABLED_DEFAULT); + appendConfig( + sb, + "Wall Profiling Enabled", + configProvider.getBoolean( + ProfilingConfig.PROFILING_WALL_ENABLED, ProfilingConfig.PROFILING_WALL_ENABLED_DEFAULT), + ProfilingConfig.PROFILING_WALL_ENABLED_DEFAULT); + appendConfig( + sb, + "Exception Profiling Enabled", + configProvider.getBoolean( + ProfilingConfig.PROFILING_EXCEPTION_ENABLED, + ProfilingConfig.PROFILING_EXCEPTION_ENABLED_DEFAULT), + ProfilingConfig.PROFILING_EXCEPTION_ENABLED_DEFAULT); + appendConfig( + sb, + "I/O Profiling Enabled", + configProvider.getBoolean( + ProfilingConfig.PROFILING_IO_ENABLED, ProfilingConfig.PROFILING_IO_ENABLED_DEFAULT), + ProfilingConfig.PROFILING_IO_ENABLED_DEFAULT); + appendConfig( + sb, + "Lock Profiling Enabled", + configProvider.getBoolean( + ProfilingConfig.PROFILING_LOCK_ENABLED, ProfilingConfig.PROFILING_LOCK_ENABLED_DEFAULT), + ProfilingConfig.PROFILING_LOCK_ENABLED_DEFAULT); + appendConfig( + sb, + "Thread Profiling Enabled", + configProvider.getBoolean( + ProfilingConfig.PROFILING_THREAD_ENABLED, + ProfilingConfig.PROFILING_THREAD_ENABLED_DEFAULT), + ProfilingConfig.PROFILING_THREAD_ENABLED_DEFAULT); + appendConfig( + sb, + "Direct Memory Profiling Enabled", + configProvider.getBoolean( + ProfilingConfig.PROFILING_DIRECT_MEMORY_ENABLED, + configProvider.getBoolean( + ProfilingConfig.PROFILING_DIRECT_ALLOCATION_ENABLED, + ProfilingConfig.PROFILING_DIRECT_MEMORY_ENABLED_DEFAULT)), + ProfilingConfig.PROFILING_DIRECT_MEMORY_ENABLED_DEFAULT); + sb.append("\n=== Allocation Profiling ===\n"); boolean allocDefault = ProfilingSupport.isObjectAllocationSampleAvailable(); boolean allocEnabled = diff --git a/dd-java-agent/agent-profiling/profiling-controller/src/main/java/com/datadog/profiling/controller/ProfilerSettingsSupport.java b/dd-java-agent/agent-profiling/profiling-controller/src/main/java/com/datadog/profiling/controller/ProfilerSettingsSupport.java index a60e6b8f1dc..81660bae4b2 100644 --- a/dd-java-agent/agent-profiling/profiling-controller/src/main/java/com/datadog/profiling/controller/ProfilerSettingsSupport.java +++ b/dd-java-agent/agent-profiling/profiling-controller/src/main/java/com/datadog/profiling/controller/ProfilerSettingsSupport.java @@ -94,6 +94,13 @@ public String toString() { protected final String uploadCompression; protected final boolean allocationProfilingEnabled; protected final boolean heapProfilingEnabled; + protected final boolean cpuProfilingEnabled; + protected final boolean wallProfilingEnabled; + protected final boolean exceptionProfilingEnabled; + protected final boolean ioProfilingEnabled; + protected final boolean lockProfilingEnabled; + protected final boolean threadProfilingEnabled; + protected final boolean directMemoryProfilingEnabled; protected final boolean startForceFirst; protected final String templateOverride; protected final int exceptionSampleLimit; @@ -141,6 +148,32 @@ protected ProfilerSettingsSupport( heapProfilingEnabled = configProvider.getBoolean( ProfilingConfig.PROFILING_HEAP_ENABLED, ProfilingSupport.isLiveHeapProfilingSafe()); + cpuProfilingEnabled = + configProvider.getBoolean( + ProfilingConfig.PROFILING_CPU_ENABLED, ProfilingConfig.PROFILING_CPU_ENABLED_DEFAULT); + wallProfilingEnabled = + configProvider.getBoolean( + ProfilingConfig.PROFILING_WALL_ENABLED, ProfilingConfig.PROFILING_WALL_ENABLED_DEFAULT); + exceptionProfilingEnabled = + configProvider.getBoolean( + ProfilingConfig.PROFILING_EXCEPTION_ENABLED, + ProfilingConfig.PROFILING_EXCEPTION_ENABLED_DEFAULT); + ioProfilingEnabled = + configProvider.getBoolean( + ProfilingConfig.PROFILING_IO_ENABLED, ProfilingConfig.PROFILING_IO_ENABLED_DEFAULT); + lockProfilingEnabled = + configProvider.getBoolean( + ProfilingConfig.PROFILING_LOCK_ENABLED, ProfilingConfig.PROFILING_LOCK_ENABLED_DEFAULT); + threadProfilingEnabled = + configProvider.getBoolean( + ProfilingConfig.PROFILING_THREAD_ENABLED, + ProfilingConfig.PROFILING_THREAD_ENABLED_DEFAULT); + directMemoryProfilingEnabled = + configProvider.getBoolean( + ProfilingConfig.PROFILING_DIRECT_MEMORY_ENABLED, + configProvider.getBoolean( + ProfilingConfig.PROFILING_DIRECT_ALLOCATION_ENABLED, + ProfilingConfig.PROFILING_DIRECT_MEMORY_ENABLED_DEFAULT)); startForceFirst = configProvider.getBoolean( ProfilingConfig.PROFILING_START_FORCE_FIRST, @@ -293,6 +326,13 @@ public String toString() { + ", uploadCompression='" + uploadCompression + '\'' + ", allocationProfilingEnabled=" + allocationProfilingEnabled + ", heapProfilingEnabled=" + heapProfilingEnabled + + ", cpuProfilingEnabled=" + cpuProfilingEnabled + + ", wallProfilingEnabled=" + wallProfilingEnabled + + ", exceptionProfilingEnabled=" + exceptionProfilingEnabled + + ", ioProfilingEnabled=" + ioProfilingEnabled + + ", lockProfilingEnabled=" + lockProfilingEnabled + + ", threadProfilingEnabled=" + threadProfilingEnabled + + ", directMemoryProfilingEnabled=" + directMemoryProfilingEnabled + ", startForceFirst=" + startForceFirst + ", templateOverride='" + templateOverride + '\'' + ", exceptionSampleLimit=" + exceptionSampleLimit 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 60c0d5c2e60..cd36591eb69 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 @@ -6,6 +6,8 @@ import static datadog.trace.api.config.ProfilingConfig.PROFILING_CONTEXT_ATTRIBUTES; import static datadog.trace.api.config.ProfilingConfig.PROFILING_CONTEXT_ATTRIBUTES_RESOURCE_NAME_ENABLED; import static datadog.trace.api.config.ProfilingConfig.PROFILING_CONTEXT_ATTRIBUTES_SPAN_NAME_ENABLED; +import static datadog.trace.api.config.ProfilingConfig.PROFILING_CPU_ENABLED; +import static datadog.trace.api.config.ProfilingConfig.PROFILING_CPU_ENABLED_DEFAULT; import static datadog.trace.api.config.ProfilingConfig.PROFILING_DATADOG_PROFILER_ALLOC_ENABLED; import static datadog.trace.api.config.ProfilingConfig.PROFILING_DATADOG_PROFILER_ALLOC_INTERVAL; import static datadog.trace.api.config.ProfilingConfig.PROFILING_DATADOG_PROFILER_ALLOC_INTERVAL_DEFAULT; @@ -51,6 +53,8 @@ import static datadog.trace.api.config.ProfilingConfig.PROFILING_STACKDEPTH; import static datadog.trace.api.config.ProfilingConfig.PROFILING_STACKDEPTH_DEFAULT; import static datadog.trace.api.config.ProfilingConfig.PROFILING_ULTRA_MINIMAL; +import static datadog.trace.api.config.ProfilingConfig.PROFILING_WALL_ENABLED; +import static datadog.trace.api.config.ProfilingConfig.PROFILING_WALL_ENABLED_DEFAULT; import static datadog.trace.api.config.TraceInstrumentationConfig.TRACE_ENABLED; import com.datadog.profiling.controller.ProfilingSupport; @@ -67,6 +71,9 @@ public class DatadogProfilerConfig { private static final Logger log = LoggerFactory.getLogger(DatadogProfilerConfig.class); public static boolean isCpuProfilerEnabled(ConfigProvider configProvider) { + if (!configProvider.getBoolean(PROFILING_CPU_ENABLED, PROFILING_CPU_ENABLED_DEFAULT)) { + return false; + } return getBoolean( configProvider, PROFILING_DATADOG_PROFILER_CPU_ENABLED, @@ -117,6 +124,9 @@ public static boolean isWallClockProfilerEnabled() { } public static boolean isWallClockProfilerEnabled(ConfigProvider configProvider) { + if (!configProvider.getBoolean(PROFILING_WALL_ENABLED, PROFILING_WALL_ENABLED_DEFAULT)) { + return false; + } boolean isUltraMinimal = getBoolean(configProvider, PROFILING_ULTRA_MINIMAL, false); boolean isTracingEnabled = configProvider.getBoolean(TRACE_ENABLED, true); boolean disableUnlessOptedIn = isUltraMinimal || !isTracingEnabled || isJ9(); @@ -242,6 +252,11 @@ public static boolean isMemoryLeakProfilingEnabled() { return isMemoryLeakProfilingEnabled(ConfigProvider.getInstance()); } + // Note: ddprof does not currently implement a native lock sampler. The unified gate + // dd.profiling.lock.enabled (PROFILING_LOCK_ENABLED) is honored by the JFR controller + // for jdk.JavaMonitorEnter. If a ddprof-based lock profiler is added in the future, + // it should check PROFILING_LOCK_ENABLED here. + public static boolean isLiveHeapSizeTrackingEnabled(ConfigProvider configProvider) { return getBoolean( configProvider, diff --git a/dd-java-agent/instrumentation/java/java-nio-1.8/src/main/java/datadog/trace/instrumentation/directbytebuffer/ByteBufferInstrumentation.java b/dd-java-agent/instrumentation/java/java-nio-1.8/src/main/java/datadog/trace/instrumentation/directbytebuffer/ByteBufferInstrumentation.java index db2f3a6f1fd..9b44f13e4a3 100644 --- a/dd-java-agent/instrumentation/java/java-nio-1.8/src/main/java/datadog/trace/instrumentation/directbytebuffer/ByteBufferInstrumentation.java +++ b/dd-java-agent/instrumentation/java/java-nio-1.8/src/main/java/datadog/trace/instrumentation/directbytebuffer/ByteBufferInstrumentation.java @@ -2,7 +2,8 @@ import static datadog.trace.agent.tooling.bytebuddy.matcher.NameMatchers.named; import static datadog.trace.api.config.ProfilingConfig.PROFILING_DIRECT_ALLOCATION_ENABLED; -import static datadog.trace.api.config.ProfilingConfig.PROFILING_DIRECT_ALLOCATION_ENABLED_DEFAULT; +import static datadog.trace.api.config.ProfilingConfig.PROFILING_DIRECT_MEMORY_ENABLED; +import static datadog.trace.api.config.ProfilingConfig.PROFILING_DIRECT_MEMORY_ENABLED_DEFAULT; import static net.bytebuddy.matcher.ElementMatchers.isMethod; import static net.bytebuddy.matcher.ElementMatchers.isStatic; import static net.bytebuddy.matcher.ElementMatchers.takesArgument; @@ -25,11 +26,13 @@ public ByteBufferInstrumentation() { @Override public boolean isEnabled() { + ConfigProvider cp = ConfigProvider.getInstance(); return JavaVirtualMachine.isJavaVersionAtLeast(11) && super.isEnabled() - && ConfigProvider.getInstance() - .getBoolean( - PROFILING_DIRECT_ALLOCATION_ENABLED, PROFILING_DIRECT_ALLOCATION_ENABLED_DEFAULT) + && cp.getBoolean( + PROFILING_DIRECT_MEMORY_ENABLED, + PROFILING_DIRECT_MEMORY_ENABLED_DEFAULT, + PROFILING_DIRECT_ALLOCATION_ENABLED) && Platform.hasJfr(); } diff --git a/dd-java-agent/instrumentation/java/java-nio-1.8/src/main/java/datadog/trace/instrumentation/directbytebuffer/DirectByteBufferInstrumentation.java b/dd-java-agent/instrumentation/java/java-nio-1.8/src/main/java/datadog/trace/instrumentation/directbytebuffer/DirectByteBufferInstrumentation.java index 3c3d8417d8b..c85ec9d6cfa 100644 --- a/dd-java-agent/instrumentation/java/java-nio-1.8/src/main/java/datadog/trace/instrumentation/directbytebuffer/DirectByteBufferInstrumentation.java +++ b/dd-java-agent/instrumentation/java/java-nio-1.8/src/main/java/datadog/trace/instrumentation/directbytebuffer/DirectByteBufferInstrumentation.java @@ -1,7 +1,8 @@ package datadog.trace.instrumentation.directbytebuffer; import static datadog.trace.api.config.ProfilingConfig.PROFILING_DIRECT_ALLOCATION_ENABLED; -import static datadog.trace.api.config.ProfilingConfig.PROFILING_DIRECT_ALLOCATION_ENABLED_DEFAULT; +import static datadog.trace.api.config.ProfilingConfig.PROFILING_DIRECT_MEMORY_ENABLED; +import static datadog.trace.api.config.ProfilingConfig.PROFILING_DIRECT_MEMORY_ENABLED_DEFAULT; import static net.bytebuddy.matcher.ElementMatchers.isConstructor; import static net.bytebuddy.matcher.ElementMatchers.takesArgument; import static net.bytebuddy.matcher.ElementMatchers.takesArguments; @@ -23,11 +24,13 @@ public DirectByteBufferInstrumentation() { @Override public boolean isEnabled() { + ConfigProvider cp = ConfigProvider.getInstance(); return JavaVirtualMachine.isJavaVersionAtLeast(11) && super.isEnabled() - && ConfigProvider.getInstance() - .getBoolean( - PROFILING_DIRECT_ALLOCATION_ENABLED, PROFILING_DIRECT_ALLOCATION_ENABLED_DEFAULT) + && cp.getBoolean( + PROFILING_DIRECT_MEMORY_ENABLED, + PROFILING_DIRECT_MEMORY_ENABLED_DEFAULT, + PROFILING_DIRECT_ALLOCATION_ENABLED) && Platform.hasJfr(); } diff --git a/dd-java-agent/instrumentation/java/java-nio-1.8/src/main/java/datadog/trace/instrumentation/directbytebuffer/FileChannelImplInstrumentation.java b/dd-java-agent/instrumentation/java/java-nio-1.8/src/main/java/datadog/trace/instrumentation/directbytebuffer/FileChannelImplInstrumentation.java index 0fac441bef8..9bbf099014a 100644 --- a/dd-java-agent/instrumentation/java/java-nio-1.8/src/main/java/datadog/trace/instrumentation/directbytebuffer/FileChannelImplInstrumentation.java +++ b/dd-java-agent/instrumentation/java/java-nio-1.8/src/main/java/datadog/trace/instrumentation/directbytebuffer/FileChannelImplInstrumentation.java @@ -2,7 +2,8 @@ import static datadog.trace.agent.tooling.bytebuddy.matcher.NameMatchers.named; import static datadog.trace.api.config.ProfilingConfig.PROFILING_DIRECT_ALLOCATION_ENABLED; -import static datadog.trace.api.config.ProfilingConfig.PROFILING_DIRECT_ALLOCATION_ENABLED_DEFAULT; +import static datadog.trace.api.config.ProfilingConfig.PROFILING_DIRECT_MEMORY_ENABLED; +import static datadog.trace.api.config.ProfilingConfig.PROFILING_DIRECT_MEMORY_ENABLED_DEFAULT; import static net.bytebuddy.matcher.ElementMatchers.isMethod; import static net.bytebuddy.matcher.ElementMatchers.takesArgument; import static net.bytebuddy.matcher.ElementMatchers.takesArguments; @@ -24,11 +25,13 @@ public FileChannelImplInstrumentation() { @Override public boolean isEnabled() { + ConfigProvider cp = ConfigProvider.getInstance(); return JavaVirtualMachine.isJavaVersionAtLeast(11) && super.isEnabled() - && ConfigProvider.getInstance() - .getBoolean( - PROFILING_DIRECT_ALLOCATION_ENABLED, PROFILING_DIRECT_ALLOCATION_ENABLED_DEFAULT) + && cp.getBoolean( + PROFILING_DIRECT_MEMORY_ENABLED, + PROFILING_DIRECT_MEMORY_ENABLED_DEFAULT, + PROFILING_DIRECT_ALLOCATION_ENABLED) && Platform.hasJfr(); } 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 c90ec39888e..7e43cb4bdc1 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 @@ -10,8 +10,42 @@ public final class ProfilingConfig { public static final String PROFILING_ENABLED = "profiling.enabled"; public static final boolean PROFILING_ENABLED_DEFAULT = false; public static final String PROFILING_ALLOCATION_ENABLED = "profiling.allocation.enabled"; + + /** + * @deprecated Not used. The actual default is computed dynamically by {@link + * datadog.trace.api.profiling.ProfilingSupport#isObjectAllocationSampleAvailable()}. + */ + @Deprecated public static final boolean PROFILING_ALLOCATION_ENABLED_DEFAULT = true; + public static final String PROFILING_HEAP_ENABLED = "profiling.heap.enabled"; - public static final boolean PROFILING_HEAP_ENABLED_DEFAULT = false; + + /** + * @deprecated The old value was {@code false}. The default is now computed dynamically via {@link + * datadog.trace.api.profiling.ProfilingSupport#isLiveHeapProfilingSafe()}. + */ + @Deprecated public static final boolean PROFILING_HEAP_ENABLED_DEFAULT = false; + + public static final String PROFILING_CPU_ENABLED = "profiling.cpu.enabled"; + public static final boolean PROFILING_CPU_ENABLED_DEFAULT = true; + public static final String PROFILING_WALL_ENABLED = "profiling.walltime.enabled"; + public static final boolean PROFILING_WALL_ENABLED_DEFAULT = true; + public static final String PROFILING_EXCEPTION_ENABLED = "profiling.exception.enabled"; + public static final boolean PROFILING_EXCEPTION_ENABLED_DEFAULT = true; + public static final String PROFILING_IO_ENABLED = "profiling.io.enabled"; + public static final boolean PROFILING_IO_ENABLED_DEFAULT = true; + public static final String PROFILING_LOCK_ENABLED = "profiling.lock.enabled"; + public static final boolean PROFILING_LOCK_ENABLED_DEFAULT = true; + public static final String PROFILING_THREAD_ENABLED = "profiling.thread.enabled"; + public static final boolean PROFILING_THREAD_ENABLED_DEFAULT = true; + + /** + * Unified gate for direct memory (native ByteBuffer / FileChannel) profiling. Replaces the + * deprecated {@link #PROFILING_DIRECT_ALLOCATION_ENABLED}. + */ + public static final String PROFILING_DIRECT_MEMORY_ENABLED = "profiling.direct.memory.enabled"; + + public static final boolean PROFILING_DIRECT_MEMORY_ENABLED_DEFAULT = false; + @Deprecated // Use dd.site instead public static final String PROFILING_URL = "profiling.url"; @Deprecated // Use dd.api-key instead @@ -79,9 +113,14 @@ public final class ProfilingConfig { public static final String PROFILING_DATADOG_PROFILER_ENABLED = "profiling.ddprof.enabled"; + /** + * @deprecated Use {@link #PROFILING_DIRECT_MEMORY_ENABLED} instead. + */ + @Deprecated public static final String PROFILING_DIRECT_ALLOCATION_ENABLED = "profiling.directallocation.enabled"; - public static final boolean PROFILING_DIRECT_ALLOCATION_ENABLED_DEFAULT = false; + + @Deprecated public static final boolean PROFILING_DIRECT_ALLOCATION_ENABLED_DEFAULT = false; public static final String PROFILING_STACKDEPTH = "profiling.stackdepth"; public static final int PROFILING_STACKDEPTH_DEFAULT = 512; diff --git a/metadata/supported-configurations.json b/metadata/supported-configurations.json index ac7935039e3..d6071fad144 100644 --- a/metadata/supported-configurations.json +++ b/metadata/supported-configurations.json @@ -2673,6 +2673,14 @@ "aliases": [] } ], + "DD_PROFILING_CPU_ENABLED": [ + { + "version": "A", + "type": "boolean", + "default": "true", + "aliases": [] + } + ], "DD_PROFILING_DDPROF_ALLOC_ENABLED": [ { "version": "A", @@ -2913,6 +2921,14 @@ "aliases": [] } ], + "DD_PROFILING_DIRECTALLOCATION_ENABLED": [ + { + "version": "A", + "type": "boolean", + "default": "false", + "aliases": ["DD_PROFILING_DIRECT_MEMORY_ENABLED"] + } + ], "DD_PROFILING_DISABLED_EVENTS": [ { "version": "A", @@ -2945,6 +2961,14 @@ "aliases": [] } ], + "DD_PROFILING_EXCEPTION_ENABLED": [ + { + "version": "A", + "type": "boolean", + "default": "true", + "aliases": [] + } + ], "DD_PROFILING_EXCEPTION_HISTOGRAM_MAX_COLLECTION_SIZE": [ { "version": "A", @@ -3081,6 +3105,14 @@ "aliases": [] } ], + "DD_PROFILING_IO_ENABLED": [ + { + "version": "A", + "type": "boolean", + "default": "true", + "aliases": [] + } + ], "DD_PROFILING_JFR_REPOSITORY_BASE": [ { "version": "A", @@ -3105,6 +3137,14 @@ "aliases": [] } ], + "DD_PROFILING_LOCK_ENABLED": [ + { + "version": "A", + "type": "boolean", + "default": "true", + "aliases": [] + } + ], "DD_PROFILING_PROXY_HOST": [ { "version": "A", @@ -3233,6 +3273,14 @@ "aliases": [] } ], + "DD_PROFILING_THREAD_ENABLED": [ + { + "version": "A", + "type": "boolean", + "default": "true", + "aliases": [] + } + ], "DD_PROFILING_TIMELINE_EVENTS_ENABLED": [ { "version": "A", @@ -3289,6 +3337,14 @@ "aliases": [] } ], + "DD_PROFILING_WALLTIME_ENABLED": [ + { + "version": "A", + "type": "boolean", + "default": "true", + "aliases": [] + } + ], "DD_PROPAGATION_EXTRACT_LOG_HEADER_NAMES_ENABLED": [ { "version": "A",