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,