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 d023d13b219..f9b980f486e 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 @@ -142,7 +142,25 @@ public static boolean getWallCollapsing(ConfigProvider configProvider) { PROFILING_DATADOG_PROFILER_WALL_COLLAPSING_DEFAULT); } + /** + * Checks whether the wall-clock context filter should be used.
+ * The context filter will make wall-clock profiler to pick candidate threads only from threads + * with attached tracing context.
+ * If context filter is not used (this method returns {@literal false}) all threads will be + * considered for wallclock sampling. + * + * @param configProvider the associated config provider + * @return {@literal true} if the wallclock sampler should use context filtering, {@literal false} + * otherwise + */ public static boolean getWallContextFilter(ConfigProvider configProvider) { + // Context filtering requires tracing to be enabled - without tracing, + // there are no span contexts to filter on, so threads would never be added + // to the filter, resulting in no walltime samples. + boolean isTracingEnabled = configProvider.getBoolean(TRACE_ENABLED, true); + if (!isTracingEnabled) { + return false; + } return getBoolean( configProvider, PROFILING_DATADOG_PROFILER_WALL_CONTEXT_FILTER, diff --git a/dd-smoke-tests/profiling-integration-tests/src/test/java/datadog/smoketest/JFRBasedProfilingIntegrationTest.java b/dd-smoke-tests/profiling-integration-tests/src/test/java/datadog/smoketest/JFRBasedProfilingIntegrationTest.java index 5030247339d..65bf000c82e 100644 --- a/dd-smoke-tests/profiling-integration-tests/src/test/java/datadog/smoketest/JFRBasedProfilingIntegrationTest.java +++ b/dd-smoke-tests/profiling-integration-tests/src/test/java/datadog/smoketest/JFRBasedProfilingIntegrationTest.java @@ -491,6 +491,80 @@ void testBogusApiKey(final TestInfo testInfo) throws Exception { 3); } + @Test + @DisplayName("Test wallclock profiling without tracing") + public void testWallclockProfilingWithoutTracing(final TestInfo testInfo) throws Exception { + Assumptions.assumeTrue(OperatingSystem.isLinux()); + testWithRetry( + () -> { + try { + targetProcess = + createProcessBuilder( + profilingServer.getPort(), + tracingServer.getPort(), + VALID_API_KEY, + 0, + PROFILING_START_DELAY_SECONDS, + PROFILING_UPLOAD_PERIOD_SECONDS, + false, + true, + "on", + 0, + logFilePath, + false) + .start(); + + Assumptions.assumeFalse(JavaVirtualMachine.isJ9()); + + final RecordedRequest request = retrieveRequest(); + assertNotNull(request); + + final List items = + FileUpload.parse( + request.getBody().readByteArray(), request.getHeader("Content-Type")); + + FileItem rawJfr = items.get(1); + assertEquals("main.jfr", rawJfr.getName()); + + assertFalse(logHasErrors(logFilePath)); + InputStream eventStream = new ByteArrayInputStream(rawJfr.get()); + eventStream = decompressStream("on", eventStream); + IItemCollection events = JfrLoaderToolkit.loadEvents(eventStream); + assertTrue(events.hasItems()); + + IItemCollection wallclockSamples = + events.apply(ItemFilters.type("datadog.MethodSample")); + assertTrue( + wallclockSamples.hasItems(), "Expected wallclock samples when tracing is disabled"); + + // Verify span context is not present + for (IItemIterable event : wallclockSamples) { + IMemberAccessor rootSpanIdAccessor = + LOCAL_ROOT_SPAN_ID.getAccessor(event.getType()); + IMemberAccessor spanIdAccessor = + SPAN_ID.getAccessor(event.getType()); + for (IItem sample : event) { + assertEquals( + 0, + rootSpanIdAccessor.getMember(sample).longValue(), + "rootSpanId should be 0 when tracing is disabled"); + assertEquals( + 0, + spanIdAccessor.getMember(sample).longValue(), + "spanId should be 0 when tracing is disabled"); + } + } + } finally { + if (targetProcess != null) { + targetProcess.destroyForcibly(); + } + targetProcess = null; + } + }, + testInfo, + 3); + } + @Test @DisplayName("Test shutdown") @Disabled("https://github.com/DataDog/dd-trace-java/pull/5213") @@ -771,7 +845,8 @@ private ProcessBuilder createProcessBuilder( asyncProfilerEnabled, withCompression, exitDelay, - logFilePath); + logFilePath, + true); } private static ProcessBuilder createProcessBuilder( @@ -785,7 +860,8 @@ private static ProcessBuilder createProcessBuilder( final boolean asyncProfilerEnabled, final String withCompression, final int exitDelay, - final Path logFilePath) { + final Path logFilePath, + final boolean tracingEnabled) { final String templateOverride = JFRBasedProfilingIntegrationTest.class .getClassLoader() @@ -803,6 +879,7 @@ private static ProcessBuilder createProcessBuilder( "-Ddd.service.name=smoke-test-java-app", "-Ddd.env=smoketest", "-Ddd.version=99", + "-Ddd.trace.enabled=" + tracingEnabled, "-Ddd.profiling.enabled=true", "-Ddd.profiling.stackdepth=" + STACK_DEPTH_LIMIT, "-Ddd.profiling.ddprof.enabled=" + asyncProfilerEnabled,