From b963213643aad645cb70afa40e7f70bd3ae1a315 Mon Sep 17 00:00:00 2001 From: jackshirazi Date: Mon, 24 Nov 2025 12:39:24 +0000 Subject: [PATCH 01/21] Update SamplingProfiler.java --- .../internal/SamplingProfiler.java | 62 +++++++++++-------- 1 file changed, 37 insertions(+), 25 deletions(-) diff --git a/inferred-spans/src/main/java/io/opentelemetry/contrib/inferredspans/internal/SamplingProfiler.java b/inferred-spans/src/main/java/io/opentelemetry/contrib/inferredspans/internal/SamplingProfiler.java index 2b5dff2b6..2b29aa229 100644 --- a/inferred-spans/src/main/java/io/opentelemetry/contrib/inferredspans/internal/SamplingProfiler.java +++ b/inferred-spans/src/main/java/io/opentelemetry/contrib/inferredspans/internal/SamplingProfiler.java @@ -43,6 +43,7 @@ import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; import java.util.concurrent.locks.LockSupport; +import java.util.concurrent.locks.ReentrantLock; import java.util.function.Supplier; import java.util.logging.Level; import java.util.logging.Logger; @@ -153,6 +154,7 @@ public class SamplingProfiler implements Runnable { @Nullable private final File tempDir; private final AsyncProfiler profiler; + private final ReentrantLock profilerLock = new ReentrantLock(); @Nullable private volatile Future profilingTask; /** @@ -394,9 +396,14 @@ public void run() { config.isNonStopProfiling() && !interrupted && postProcessingEnabled; setProfilingSessionOngoing(continueProfilingSession); - if (!interrupted && !scheduler.isShutdown()) { - long delay = config.getProfilingInterval().toMillis() - profilingDuration.toMillis(); - profilingTask = scheduler.schedule(this, delay, TimeUnit.MILLISECONDS); + profilerLock.lock(); + try { + if (!isInterrupted && !scheduler.isShutdown()) { + long delay = config.getProfilingInterval().toMillis() - profilingDuration.toMillis(); + profilingTask = scheduler.schedule(this, delay, TimeUnit.MILLISECONDS); + } + } finally { + profilerLock.unlock(); } } @@ -406,25 +413,25 @@ private void profile(Duration profilingDuration) throws Exception { String startCommand = createStartCommand(); String startMessage = profiler.execute(startCommand); logger.fine(startMessage); - if (!profiledThreads.isEmpty()) { - restoreFilterState(profiler); + try { + if (!profiledThreads.isEmpty()) { + restoreFilterState(profiler); + } + // Doesn't need to be atomic as this field is being updated only by a single thread + profilingSessions++; + + // When post-processing is disabled activation events are ignored, but we still need to + // invoke this method as it is the one enforcing the sampling session duration. As a side + // effect it will also consume residual activation events if post-processing is disabled + // dynamically + consumeActivationEventsFromRingBufferAndWriteToFile(profilingDuration); + } finally { + String stopMessage = profiler.execute("stop"); + logger.fine(stopMessage); } - // Doesn't need to be atomic as this field is being updated only by a single thread - profilingSessions++; - - // When post-processing is disabled activation events are ignored, but we still need to invoke - // this method - // as it is the one enforcing the sampling session duration. As a side effect it will also - // consume - // residual activation events if post-processing is disabled dynamically - consumeActivationEventsFromRingBufferAndWriteToFile(profilingDuration); - - String stopMessage = profiler.execute("stop"); - logger.fine(stopMessage); // When post-processing is disabled, jfr file will not be parsed and the heavy processing will - // not occur - // as this method aborts when no activation events are buffered + // not occur as this method aborts when no activation events are buffered processTraces(); } catch (InterruptedException | ClosedByInterruptException e) { try { @@ -739,13 +746,18 @@ public void start() { @SuppressWarnings({"FutureReturnValueIgnored", "Interruption"}) public void reschedule() { - Future future = this.profilingTask; - if (future != null) { - if (future.cancel(true)) { - Duration profilingDuration = config.getProfilingDuration(); - long delay = config.getProfilingInterval().toMillis() - profilingDuration.toMillis(); - profilingTask = scheduler.schedule(this, delay, TimeUnit.MILLISECONDS); + profilerLock.lock(); + try { + Future future = this.profilingTask; + if (future != null) { + if (future.cancel(true)) { + Duration profilingDuration = config.getProfilingDuration(); + long delay = config.getProfilingInterval().toMillis() - profilingDuration.toMillis(); + profilingTask = scheduler.schedule(this, delay, TimeUnit.MILLISECONDS); + } } + } finally { + profilerLock.unlock(); } } From a8ba1cbc42979f7bbe83d093e23dfda32e69000f Mon Sep 17 00:00:00 2001 From: jackshirazi Date: Mon, 24 Nov 2025 13:35:55 +0000 Subject: [PATCH 02/21] Update inferred-spans/src/main/java/io/opentelemetry/contrib/inferredspans/internal/SamplingProfiler.java --- .../contrib/inferredspans/internal/SamplingProfiler.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/inferred-spans/src/main/java/io/opentelemetry/contrib/inferredspans/internal/SamplingProfiler.java b/inferred-spans/src/main/java/io/opentelemetry/contrib/inferredspans/internal/SamplingProfiler.java index 2b29aa229..15d2428a8 100644 --- a/inferred-spans/src/main/java/io/opentelemetry/contrib/inferredspans/internal/SamplingProfiler.java +++ b/inferred-spans/src/main/java/io/opentelemetry/contrib/inferredspans/internal/SamplingProfiler.java @@ -398,7 +398,7 @@ public void run() { profilerLock.lock(); try { - if (!isInterrupted && !scheduler.isShutdown()) { + if (!Thread.currentThread().isInterrupted() && !scheduler.isShutdown()) { long delay = config.getProfilingInterval().toMillis() - profilingDuration.toMillis(); profilingTask = scheduler.schedule(this, delay, TimeUnit.MILLISECONDS); } From b065a8d003c00ffe80cc40a0c117aae7a5f601ec Mon Sep 17 00:00:00 2001 From: Jack Shirazi Date: Fri, 5 Dec 2025 15:05:15 +0000 Subject: [PATCH 03/21] review feedback --- .../inferredspans/internal/SamplingProfiler.java | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/inferred-spans/src/main/java/io/opentelemetry/contrib/inferredspans/internal/SamplingProfiler.java b/inferred-spans/src/main/java/io/opentelemetry/contrib/inferredspans/internal/SamplingProfiler.java index 15d2428a8..5e6b3a1a2 100644 --- a/inferred-spans/src/main/java/io/opentelemetry/contrib/inferredspans/internal/SamplingProfiler.java +++ b/inferred-spans/src/main/java/io/opentelemetry/contrib/inferredspans/internal/SamplingProfiler.java @@ -398,6 +398,9 @@ public void run() { profilerLock.lock(); try { + // it's possible for an interruption to occur just before the lock was acquired. This is + // handled by re-reading Thread.currentThread().isInterrupted() to ensure no task is scheduled + // if an interruption occurred just before acquiring the lock if (!Thread.currentThread().isInterrupted() && !scheduler.isShutdown()) { long delay = config.getProfilingInterval().toMillis() - profilingDuration.toMillis(); profilingTask = scheduler.schedule(this, delay, TimeUnit.MILLISECONDS); @@ -414,6 +417,8 @@ private void profile(Duration profilingDuration) throws Exception { String startMessage = profiler.execute(startCommand); logger.fine(startMessage); try { + // try-finally because if the code is interrupted we want to ensure the + // profiler.execute("stop") is called if (!profiledThreads.isEmpty()) { restoreFilterState(profiler); } @@ -749,12 +754,10 @@ public void reschedule() { profilerLock.lock(); try { Future future = this.profilingTask; - if (future != null) { - if (future.cancel(true)) { - Duration profilingDuration = config.getProfilingDuration(); - long delay = config.getProfilingInterval().toMillis() - profilingDuration.toMillis(); - profilingTask = scheduler.schedule(this, delay, TimeUnit.MILLISECONDS); - } + if (future != null && future.cancel(true)) { + Duration profilingDuration = config.getProfilingDuration(); + long delay = config.getProfilingInterval().toMillis() - profilingDuration.toMillis(); + profilingTask = scheduler.schedule(this, delay, TimeUnit.MILLISECONDS); } } finally { profilerLock.unlock(); From 30aa33ad702bfedc13a16c0c73e4d5be09231a1f Mon Sep 17 00:00:00 2001 From: Jack Shirazi Date: Mon, 8 Dec 2025 15:51:57 +0000 Subject: [PATCH 04/21] end previous session quicker --- .../contrib/inferredspans/internal/SamplingProfiler.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/inferred-spans/src/main/java/io/opentelemetry/contrib/inferredspans/internal/SamplingProfiler.java b/inferred-spans/src/main/java/io/opentelemetry/contrib/inferredspans/internal/SamplingProfiler.java index 5e6b3a1a2..e213965e9 100644 --- a/inferred-spans/src/main/java/io/opentelemetry/contrib/inferredspans/internal/SamplingProfiler.java +++ b/inferred-spans/src/main/java/io/opentelemetry/contrib/inferredspans/internal/SamplingProfiler.java @@ -766,6 +766,9 @@ public void reschedule() { public void stop() throws InterruptedException, IOException { // cancels/interrupts the profiling thread + if (profilingTask != null) { + profilingTask.cancel(true); + } // implicitly clears profiled threads scheduler.shutdown(); scheduler.awaitTermination(10, TimeUnit.SECONDS); From cd3b46baa7051ce2a5e805d5ce8f118a354a3891 Mon Sep 17 00:00:00 2001 From: Jack Shirazi Date: Mon, 8 Dec 2025 15:59:19 +0000 Subject: [PATCH 05/21] suppress interruption warning --- .../contrib/inferredspans/internal/SamplingProfiler.java | 1 + 1 file changed, 1 insertion(+) diff --git a/inferred-spans/src/main/java/io/opentelemetry/contrib/inferredspans/internal/SamplingProfiler.java b/inferred-spans/src/main/java/io/opentelemetry/contrib/inferredspans/internal/SamplingProfiler.java index e213965e9..b2696e725 100644 --- a/inferred-spans/src/main/java/io/opentelemetry/contrib/inferredspans/internal/SamplingProfiler.java +++ b/inferred-spans/src/main/java/io/opentelemetry/contrib/inferredspans/internal/SamplingProfiler.java @@ -767,6 +767,7 @@ public void reschedule() { public void stop() throws InterruptedException, IOException { // cancels/interrupts the profiling thread if (profilingTask != null) { + @SuppressWarnings("Interruption") profilingTask.cancel(true); } // implicitly clears profiled threads From 3765386baff7da423cee1646e675c7ce435d6e27 Mon Sep 17 00:00:00 2001 From: Jack Shirazi Date: Mon, 8 Dec 2025 16:06:15 +0000 Subject: [PATCH 06/21] spotless --- .../contrib/inferredspans/internal/SamplingProfiler.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/inferred-spans/src/main/java/io/opentelemetry/contrib/inferredspans/internal/SamplingProfiler.java b/inferred-spans/src/main/java/io/opentelemetry/contrib/inferredspans/internal/SamplingProfiler.java index b2696e725..05ecd889d 100644 --- a/inferred-spans/src/main/java/io/opentelemetry/contrib/inferredspans/internal/SamplingProfiler.java +++ b/inferred-spans/src/main/java/io/opentelemetry/contrib/inferredspans/internal/SamplingProfiler.java @@ -764,10 +764,10 @@ public void reschedule() { } } + @SuppressWarnings({"FutureReturnValueIgnored", "Interruption"}) public void stop() throws InterruptedException, IOException { // cancels/interrupts the profiling thread if (profilingTask != null) { - @SuppressWarnings("Interruption") profilingTask.cancel(true); } // implicitly clears profiled threads From 373a94736dbbf2ac8e296d71583eca99fb58c4b8 Mon Sep 17 00:00:00 2001 From: Jack Shirazi Date: Mon, 8 Dec 2025 16:54:57 +0000 Subject: [PATCH 07/21] handle empty files sent to the jfr parser --- .../inferredspans/internal/asyncprofiler/JfrParser.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/inferred-spans/src/main/java/io/opentelemetry/contrib/inferredspans/internal/asyncprofiler/JfrParser.java b/inferred-spans/src/main/java/io/opentelemetry/contrib/inferredspans/internal/asyncprofiler/JfrParser.java index 44c6f9c13..fcb3a19e4 100644 --- a/inferred-spans/src/main/java/io/opentelemetry/contrib/inferredspans/internal/asyncprofiler/JfrParser.java +++ b/inferred-spans/src/main/java/io/opentelemetry/contrib/inferredspans/internal/asyncprofiler/JfrParser.java @@ -93,6 +93,9 @@ public void parse( this.includedClasses = includedClasses; bufferedFile.setFile(file); long fileSize = bufferedFile.size(); + if (fileSize == 0) { + return; + } int chunkSize = readChunk(0); if (chunkSize < fileSize) { From 7ecda2da0bbfebdb322579d27952d2ce8dd877f5 Mon Sep 17 00:00:00 2001 From: Jack Shirazi Date: Mon, 8 Dec 2025 16:58:06 +0000 Subject: [PATCH 08/21] ensure that a running profiler is stopped then started when a new test is run --- .../inferredspans/internal/SamplingProfiler.java | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/inferred-spans/src/main/java/io/opentelemetry/contrib/inferredspans/internal/SamplingProfiler.java b/inferred-spans/src/main/java/io/opentelemetry/contrib/inferredspans/internal/SamplingProfiler.java index 05ecd889d..ec46db0b6 100644 --- a/inferred-spans/src/main/java/io/opentelemetry/contrib/inferredspans/internal/SamplingProfiler.java +++ b/inferred-spans/src/main/java/io/opentelemetry/contrib/inferredspans/internal/SamplingProfiler.java @@ -414,7 +414,21 @@ public void run() { private void profile(Duration profilingDuration) throws Exception { try { String startCommand = createStartCommand(); - String startMessage = profiler.execute(startCommand); + String startMessage; + try { + startMessage = profiler.execute(startCommand); + } catch (IllegalStateException e) { + if (e.getMessage() != null && e.getMessage().contains("already started")) { + logger.fine("Profiler already started. Stopping and restarting."); + try { + profiler.stop(); + } catch (Exception ignore) { + } + startMessage = profiler.execute(startCommand); + } else { + throw e; + } + } logger.fine(startMessage); try { // try-finally because if the code is interrupted we want to ensure the From 6678fc66d9ab11c87d1c58d15fe6905e26357e74 Mon Sep 17 00:00:00 2001 From: Jack Shirazi Date: Mon, 8 Dec 2025 17:06:19 +0000 Subject: [PATCH 09/21] ignore error --- .../contrib/inferredspans/internal/SamplingProfiler.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/inferred-spans/src/main/java/io/opentelemetry/contrib/inferredspans/internal/SamplingProfiler.java b/inferred-spans/src/main/java/io/opentelemetry/contrib/inferredspans/internal/SamplingProfiler.java index ec46db0b6..25d1af328 100644 --- a/inferred-spans/src/main/java/io/opentelemetry/contrib/inferredspans/internal/SamplingProfiler.java +++ b/inferred-spans/src/main/java/io/opentelemetry/contrib/inferredspans/internal/SamplingProfiler.java @@ -422,7 +422,8 @@ private void profile(Duration profilingDuration) throws Exception { logger.fine("Profiler already started. Stopping and restarting."); try { profiler.stop(); - } catch (Exception ignore) { + } catch (RuntimeException ignore) { + logger.log(Level.FINE, "Ignored error on stopping profiler", ignore); } startMessage = profiler.execute(startCommand); } else { From 40834c4c14d111b146c3426873e77ed7986714f5 Mon Sep 17 00:00:00 2001 From: Jack Shirazi Date: Mon, 8 Dec 2025 20:07:27 +0000 Subject: [PATCH 10/21] move temp dir to control of unit test framework --- .../inferredspans/InferredSpansProcessor.java | 6 ++++-- .../InferredSpansProcessorBuilder.java | 13 ++++++++++--- .../contrib/inferredspans/InferredSpansTest.java | 11 ++++++++--- .../internal/SamplingProfilerTest.java | 15 ++++----------- 4 files changed, 26 insertions(+), 19 deletions(-) diff --git a/inferred-spans/src/main/java/io/opentelemetry/contrib/inferredspans/InferredSpansProcessor.java b/inferred-spans/src/main/java/io/opentelemetry/contrib/inferredspans/InferredSpansProcessor.java index 27d1da9b7..4a8c1630b 100644 --- a/inferred-spans/src/main/java/io/opentelemetry/contrib/inferredspans/InferredSpansProcessor.java +++ b/inferred-spans/src/main/java/io/opentelemetry/contrib/inferredspans/InferredSpansProcessor.java @@ -49,10 +49,12 @@ public class InferredSpansProcessor implements SpanProcessor { SpanAnchoredClock clock, boolean startScheduledProfiling, @Nullable File activationEventsFile, - @Nullable File jfrFile) { + @Nullable File jfrFile, + @Nullable File tempDir) { this.config = config; profiler = - new SamplingProfiler(config, clock, this::getTracer, activationEventsFile, jfrFile, null); + new SamplingProfiler( + config, clock, this::getTracer, activationEventsFile, jfrFile, tempDir); if (startScheduledProfiling) { profiler.start(); } diff --git a/inferred-spans/src/main/java/io/opentelemetry/contrib/inferredspans/InferredSpansProcessorBuilder.java b/inferred-spans/src/main/java/io/opentelemetry/contrib/inferredspans/InferredSpansProcessorBuilder.java index a96f3b942..5d93e4b8e 100644 --- a/inferred-spans/src/main/java/io/opentelemetry/contrib/inferredspans/InferredSpansProcessorBuilder.java +++ b/inferred-spans/src/main/java/io/opentelemetry/contrib/inferredspans/InferredSpansProcessorBuilder.java @@ -52,6 +52,7 @@ public class InferredSpansProcessorBuilder { private boolean startScheduledProfiling = true; @Nullable private File activationEventsFile = null; @Nullable private File jfrFile = null; + @Nullable private File tempDir = null; private BiConsumer parentOverrideHandler = CallTree.DEFAULT_PARENT_OVERRIDE; @@ -75,7 +76,7 @@ public InferredSpansProcessor build() { parentOverrideHandler); InferredSpansProcessor processor = new InferredSpansProcessor( - config, clock, startScheduledProfiling, activationEventsFile, jfrFile); + config, clock, startScheduledProfiling, activationEventsFile, jfrFile, tempDir); InferredSpans.setInstance(processor); return processor; } @@ -194,17 +195,23 @@ public InferredSpansProcessorBuilder startScheduledProfiling(boolean startSchedu } /** For testing only. */ - InferredSpansProcessorBuilder activationEventsFile(@Nullable File activationEventsFile) { + public InferredSpansProcessorBuilder activationEventsFile(@Nullable File activationEventsFile) { this.activationEventsFile = activationEventsFile; return this; } /** For testing only. */ - InferredSpansProcessorBuilder jfrFile(@Nullable File jfrFile) { + public InferredSpansProcessorBuilder jfrFile(@Nullable File jfrFile) { this.jfrFile = jfrFile; return this; } + /** For testing only. */ + public InferredSpansProcessorBuilder tempDir(@Nullable File tempDir) { + this.tempDir = tempDir; + return this; + } + /** * Defines the action to perform when a inferred span is discovered to actually be the parent of a * normal span. The first argument of the handler is the modifiable inferred span, the second diff --git a/inferred-spans/src/test/java/io/opentelemetry/contrib/inferredspans/InferredSpansTest.java b/inferred-spans/src/test/java/io/opentelemetry/contrib/inferredspans/InferredSpansTest.java index e0de5997e..939f3003f 100644 --- a/inferred-spans/src/test/java/io/opentelemetry/contrib/inferredspans/InferredSpansTest.java +++ b/inferred-spans/src/test/java/io/opentelemetry/contrib/inferredspans/InferredSpansTest.java @@ -10,17 +10,20 @@ import io.opentelemetry.contrib.inferredspans.internal.SamplingProfiler; import io.opentelemetry.contrib.inferredspans.internal.util.DisabledOnOpenJ9; +import java.nio.file.Path; import java.time.Duration; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.condition.DisabledOnOs; import org.junit.jupiter.api.condition.OS; +import org.junit.jupiter.api.io.TempDir; @DisabledOnOs(OS.WINDOWS) @DisabledOnOpenJ9 class InferredSpansTest { + @TempDir Path tempDir; private ProfilerTestSetup setup; @BeforeEach @@ -40,7 +43,7 @@ void tearDown() { void testIsEnabled() { assertThat(InferredSpans.isEnabled()).isFalse(); - setup = ProfilerTestSetup.create(c -> {}); + setup = ProfilerTestSetup.create(c -> c.tempDir(tempDir.toFile())); assertThat(InferredSpans.isEnabled()).isTrue(); @@ -61,7 +64,8 @@ void testSetProfilerIntervalWhenDisabled() { ProfilerTestSetup.create( c -> c.profilerInterval(Duration.ofSeconds(10)) - .profilingDuration(Duration.ofMillis(500))); + .profilingDuration(Duration.ofMillis(500)) + .tempDir(tempDir.toFile())); // assert that the interval set before the profiler was initialized is ignored assertThat(setup.profiler.getConfig().getProfilingInterval()).isEqualTo(Duration.ofSeconds(10)); @@ -73,7 +77,8 @@ void testSetProfilerInterval() { ProfilerTestSetup.create( c -> c.profilerInterval(Duration.ofSeconds(10)) - .profilingDuration(Duration.ofMillis(500))); + .profilingDuration(Duration.ofMillis(500)) + .tempDir(tempDir.toFile())); SamplingProfiler profiler = setup.profiler; await() diff --git a/inferred-spans/src/test/java/io/opentelemetry/contrib/inferredspans/internal/SamplingProfilerTest.java b/inferred-spans/src/test/java/io/opentelemetry/contrib/inferredspans/internal/SamplingProfilerTest.java index 327077f85..1e173b0b4 100644 --- a/inferred-spans/src/test/java/io/opentelemetry/contrib/inferredspans/internal/SamplingProfilerTest.java +++ b/inferred-spans/src/test/java/io/opentelemetry/contrib/inferredspans/internal/SamplingProfilerTest.java @@ -22,7 +22,6 @@ import java.lang.reflect.Method; import java.nio.file.Files; import java.nio.file.Path; -import java.nio.file.Paths; import java.time.Duration; import java.util.List; import java.util.Optional; @@ -58,12 +57,6 @@ void tearDown() { @Test void shouldLazilyCreateTempFilesAndCleanThem() { - for (Path file : getProfilerTempFiles()) { - if (!file.toFile().delete()) { - throw new IllegalStateException("Could not delete temp file: " + file); - } - } - // temporary files should be created on-demand, and properly deleted afterwards setupProfiler(false); @@ -91,9 +84,8 @@ void shouldLazilyCreateTempFilesAndCleanThem() { .isEmpty(); } - private static List getProfilerTempFiles() { - Path tempFolder = Paths.get(System.getProperty("java.io.tmpdir")); - try (Stream files = Files.list(tempFolder)) { + private List getProfilerTempFiles() { + try (Stream files = Files.list(tempDir)) { return files .filter(f -> f.getFileName().toString().startsWith("otel-inferred-")) .sorted() @@ -327,7 +319,8 @@ private void setupProfiler(Consumer configCustomi config .profilingDuration(Duration.ofMillis(500)) .profilerInterval(Duration.ofMillis(500)) - .samplingInterval(Duration.ofMillis(5)); + .samplingInterval(Duration.ofMillis(5)) + .tempDir(tempDir.toFile()); configCustomizer.accept(config); }); } From 500018f1ae3bb9797fc3d6ca84e74e5148436a82 Mon Sep 17 00:00:00 2001 From: Jack Shirazi Date: Mon, 8 Dec 2025 20:48:45 +0000 Subject: [PATCH 11/21] don't postprocess if it's disabled --- .../contrib/inferredspans/internal/SamplingProfiler.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/inferred-spans/src/main/java/io/opentelemetry/contrib/inferredspans/internal/SamplingProfiler.java b/inferred-spans/src/main/java/io/opentelemetry/contrib/inferredspans/internal/SamplingProfiler.java index 25d1af328..2e18d2259 100644 --- a/inferred-spans/src/main/java/io/opentelemetry/contrib/inferredspans/internal/SamplingProfiler.java +++ b/inferred-spans/src/main/java/io/opentelemetry/contrib/inferredspans/internal/SamplingProfiler.java @@ -532,6 +532,9 @@ EventPoller.PollState consumeActivationEventsFromRingBufferAndWriteToFile() thro } public void processTraces() throws IOException { + if (!config.isPostProcessingEnabled()) { + return; + } if (jfrParser == null) { jfrParser = new JfrParser(); } From 7101cfb3792061e225e6885b25c804df2c0f281d Mon Sep 17 00:00:00 2001 From: Jack Shirazi Date: Mon, 8 Dec 2025 21:07:44 +0000 Subject: [PATCH 12/21] statically initialize ProfilingActivationListener in test --- .../contrib/inferredspans/internal/SamplingProfilerTest.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/inferred-spans/src/test/java/io/opentelemetry/contrib/inferredspans/internal/SamplingProfilerTest.java b/inferred-spans/src/test/java/io/opentelemetry/contrib/inferredspans/internal/SamplingProfilerTest.java index 1e173b0b4..d16db10b4 100644 --- a/inferred-spans/src/test/java/io/opentelemetry/contrib/inferredspans/internal/SamplingProfilerTest.java +++ b/inferred-spans/src/test/java/io/opentelemetry/contrib/inferredspans/internal/SamplingProfilerTest.java @@ -43,6 +43,10 @@ @DisabledOnOpenJ9 class SamplingProfilerTest { + static { + ProfilingActivationListener.ensureInitialized(); + } + private ProfilerTestSetup setup; @TempDir private Path tempDir; From 1dbda97bc035e6b3122f1b841350af0ffb7019b4 Mon Sep 17 00:00:00 2001 From: Jack Shirazi Date: Mon, 8 Dec 2025 21:18:09 +0000 Subject: [PATCH 13/21] fake comment to bump for more test runs --- .../contrib/inferredspans/internal/SamplingProfiler.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/inferred-spans/src/main/java/io/opentelemetry/contrib/inferredspans/internal/SamplingProfiler.java b/inferred-spans/src/main/java/io/opentelemetry/contrib/inferredspans/internal/SamplingProfiler.java index 2e18d2259..bd29a1435 100644 --- a/inferred-spans/src/main/java/io/opentelemetry/contrib/inferredspans/internal/SamplingProfiler.java +++ b/inferred-spans/src/main/java/io/opentelemetry/contrib/inferredspans/internal/SamplingProfiler.java @@ -101,7 +101,7 @@ * stack trace}. */ public class SamplingProfiler implements Runnable { - + // fake comment to bump for more test runs private static final String LIB_DIR_PROPERTY_NAME = "one.profiler.extractPath"; private static final Logger logger = Logger.getLogger(SamplingProfiler.class.getName()); From 8fa0815a31c2440c016ae1477ae62c8d229b7bad Mon Sep 17 00:00:00 2001 From: Jack Shirazi Date: Mon, 8 Dec 2025 22:23:23 +0000 Subject: [PATCH 14/21] test out partly forcing post processing --- .../contrib/inferredspans/internal/SamplingProfiler.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/inferred-spans/src/main/java/io/opentelemetry/contrib/inferredspans/internal/SamplingProfiler.java b/inferred-spans/src/main/java/io/opentelemetry/contrib/inferredspans/internal/SamplingProfiler.java index bd29a1435..fa43989d3 100644 --- a/inferred-spans/src/main/java/io/opentelemetry/contrib/inferredspans/internal/SamplingProfiler.java +++ b/inferred-spans/src/main/java/io/opentelemetry/contrib/inferredspans/internal/SamplingProfiler.java @@ -101,7 +101,7 @@ * stack trace}. */ public class SamplingProfiler implements Runnable { - // fake comment to bump for more test runs + private static final String LIB_DIR_PROPERTY_NAME = "one.profiler.extractPath"; private static final Logger logger = Logger.getLogger(SamplingProfiler.class.getName()); @@ -375,7 +375,9 @@ public void run() { Duration profilingDuration = config.getProfilingDuration(); boolean postProcessingEnabled = config.isPostProcessingEnabled(); - setProfilingSessionOngoing(postProcessingEnabled); + // We need to enable the session so that onActivation is called and threads are added to the + // profiler (profiler.addThread). Otherwise, with the "filter" option, nothing is profiled. + setProfilingSessionOngoing(true); if (postProcessingEnabled) { logger.fine("Start full profiling session (async-profiler and agent processing)"); From 1b5207cc9d54781d225e791d379ff7226a3b7339 Mon Sep 17 00:00:00 2001 From: Jack Shirazi Date: Mon, 8 Dec 2025 22:44:24 +0000 Subject: [PATCH 15/21] fake comment again to bump for more test runs --- .../contrib/inferredspans/internal/SamplingProfiler.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/inferred-spans/src/main/java/io/opentelemetry/contrib/inferredspans/internal/SamplingProfiler.java b/inferred-spans/src/main/java/io/opentelemetry/contrib/inferredspans/internal/SamplingProfiler.java index fa43989d3..deeafb906 100644 --- a/inferred-spans/src/main/java/io/opentelemetry/contrib/inferredspans/internal/SamplingProfiler.java +++ b/inferred-spans/src/main/java/io/opentelemetry/contrib/inferredspans/internal/SamplingProfiler.java @@ -101,7 +101,7 @@ * stack trace}. */ public class SamplingProfiler implements Runnable { - + // fake comment to bump for more test runs private static final String LIB_DIR_PROPERTY_NAME = "one.profiler.extractPath"; private static final Logger logger = Logger.getLogger(SamplingProfiler.class.getName()); From da32568dcc9e44dccff2c042721a9aebaa3da207 Mon Sep 17 00:00:00 2001 From: Jack Shirazi Date: Mon, 8 Dec 2025 23:03:48 +0000 Subject: [PATCH 16/21] test out further post processing handling --- .../contrib/inferredspans/internal/SamplingProfiler.java | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/inferred-spans/src/main/java/io/opentelemetry/contrib/inferredspans/internal/SamplingProfiler.java b/inferred-spans/src/main/java/io/opentelemetry/contrib/inferredspans/internal/SamplingProfiler.java index deeafb906..d272f52b9 100644 --- a/inferred-spans/src/main/java/io/opentelemetry/contrib/inferredspans/internal/SamplingProfiler.java +++ b/inferred-spans/src/main/java/io/opentelemetry/contrib/inferredspans/internal/SamplingProfiler.java @@ -101,7 +101,7 @@ * stack trace}. */ public class SamplingProfiler implements Runnable { - // fake comment to bump for more test runs + private static final String LIB_DIR_PROPERTY_NAME = "one.profiler.extractPath"; private static final Logger logger = Logger.getLogger(SamplingProfiler.class.getName()); @@ -319,6 +319,9 @@ public boolean onActivation(Span activeSpan, @Nullable Span previouslyActive) { if (previouslyActive == null) { profiler.addThread(Thread.currentThread()); } + if (!config.isPostProcessingEnabled()) { + return true; + } boolean success = eventBuffer.tryPublishEvent(activationEventTranslator, activeSpan, previouslyActive); if (!success) { @@ -345,6 +348,9 @@ public boolean onDeactivation(Span deactivatedSpan, @Nullable Span previouslyAct if (previouslyActive == null) { profiler.removeThread(Thread.currentThread()); } + if (!config.isPostProcessingEnabled()) { + return true; + } boolean success = eventBuffer.tryPublishEvent( deactivationEventTranslator, deactivatedSpan, previouslyActive); From 2113a0ad7ccd539ce0b5a2653f09ee6a1f4f956b Mon Sep 17 00:00:00 2001 From: Jack Shirazi Date: Mon, 8 Dec 2025 23:17:58 +0000 Subject: [PATCH 17/21] fake comment again2 to bump for more test runs --- .../contrib/inferredspans/internal/SamplingProfiler.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/inferred-spans/src/main/java/io/opentelemetry/contrib/inferredspans/internal/SamplingProfiler.java b/inferred-spans/src/main/java/io/opentelemetry/contrib/inferredspans/internal/SamplingProfiler.java index d272f52b9..a2ff08e91 100644 --- a/inferred-spans/src/main/java/io/opentelemetry/contrib/inferredspans/internal/SamplingProfiler.java +++ b/inferred-spans/src/main/java/io/opentelemetry/contrib/inferredspans/internal/SamplingProfiler.java @@ -101,7 +101,7 @@ * stack trace}. */ public class SamplingProfiler implements Runnable { - + // fake comment to bump for more test runs private static final String LIB_DIR_PROPERTY_NAME = "one.profiler.extractPath"; private static final Logger logger = Logger.getLogger(SamplingProfiler.class.getName()); From 010cac8ced95e8fd98094cf5a588057172943321 Mon Sep 17 00:00:00 2001 From: Jack Shirazi Date: Mon, 8 Dec 2025 23:32:12 +0000 Subject: [PATCH 18/21] remove fake comment --- .../contrib/inferredspans/internal/SamplingProfiler.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/inferred-spans/src/main/java/io/opentelemetry/contrib/inferredspans/internal/SamplingProfiler.java b/inferred-spans/src/main/java/io/opentelemetry/contrib/inferredspans/internal/SamplingProfiler.java index a2ff08e91..d272f52b9 100644 --- a/inferred-spans/src/main/java/io/opentelemetry/contrib/inferredspans/internal/SamplingProfiler.java +++ b/inferred-spans/src/main/java/io/opentelemetry/contrib/inferredspans/internal/SamplingProfiler.java @@ -101,7 +101,7 @@ * stack trace}. */ public class SamplingProfiler implements Runnable { - // fake comment to bump for more test runs + private static final String LIB_DIR_PROPERTY_NAME = "one.profiler.extractPath"; private static final Logger logger = Logger.getLogger(SamplingProfiler.class.getName()); From 126ef4b208b31abec59132d1feebf45dae8b1c85 Mon Sep 17 00:00:00 2001 From: Jack Shirazi Date: Thu, 11 Dec 2025 12:17:27 +0000 Subject: [PATCH 19/21] add empty file parse test --- .../internal/asyncprofiler/JfrParserTest.java | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/inferred-spans/src/test/java/io/opentelemetry/contrib/inferredspans/internal/asyncprofiler/JfrParserTest.java b/inferred-spans/src/test/java/io/opentelemetry/contrib/inferredspans/internal/asyncprofiler/JfrParserTest.java index 60273534b..dd67a3a71 100644 --- a/inferred-spans/src/test/java/io/opentelemetry/contrib/inferredspans/internal/asyncprofiler/JfrParserTest.java +++ b/inferred-spans/src/test/java/io/opentelemetry/contrib/inferredspans/internal/asyncprofiler/JfrParserTest.java @@ -60,4 +60,16 @@ void name() throws Exception { }); assertThat(stackTraces.get()).isEqualTo(92); } + + @Test + void testParseEmptyFile() throws Exception { + File file = File.createTempFile("empty", ".jfr"); + try { + JfrParser jfrParser = new JfrParser(); + jfrParser.parse(file, Collections.emptyList(), Collections.emptyList()); + jfrParser.consumeStackTraces((threadId, stackTraceId, nanoTime) -> {}); + } finally { + file.delete(); + } + } } From 1c85f06f8802ae22e236dcacdc9c9227d2bd6003 Mon Sep 17 00:00:00 2001 From: Jack Shirazi Date: Thu, 11 Dec 2025 13:56:13 +0000 Subject: [PATCH 20/21] fix access modifiers, no need for public API --- .../contrib/inferredspans/InferredSpansProcessorBuilder.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/inferred-spans/src/main/java/io/opentelemetry/contrib/inferredspans/InferredSpansProcessorBuilder.java b/inferred-spans/src/main/java/io/opentelemetry/contrib/inferredspans/InferredSpansProcessorBuilder.java index 5d93e4b8e..ee30d6b13 100644 --- a/inferred-spans/src/main/java/io/opentelemetry/contrib/inferredspans/InferredSpansProcessorBuilder.java +++ b/inferred-spans/src/main/java/io/opentelemetry/contrib/inferredspans/InferredSpansProcessorBuilder.java @@ -195,13 +195,13 @@ public InferredSpansProcessorBuilder startScheduledProfiling(boolean startSchedu } /** For testing only. */ - public InferredSpansProcessorBuilder activationEventsFile(@Nullable File activationEventsFile) { + InferredSpansProcessorBuilder activationEventsFile(@Nullable File activationEventsFile) { this.activationEventsFile = activationEventsFile; return this; } /** For testing only. */ - public InferredSpansProcessorBuilder jfrFile(@Nullable File jfrFile) { + InferredSpansProcessorBuilder jfrFile(@Nullable File jfrFile) { this.jfrFile = jfrFile; return this; } From 0bfc2574fff89dd5a4190db8f2c18c5b12d84088 Mon Sep 17 00:00:00 2001 From: Jack Shirazi Date: Fri, 12 Dec 2025 10:20:04 +0000 Subject: [PATCH 21/21] bump for gh flakiness --- .../contrib/inferredspans/internal/SamplingProfilerTest.java | 1 + 1 file changed, 1 insertion(+) diff --git a/inferred-spans/src/test/java/io/opentelemetry/contrib/inferredspans/internal/SamplingProfilerTest.java b/inferred-spans/src/test/java/io/opentelemetry/contrib/inferredspans/internal/SamplingProfilerTest.java index d16db10b4..6471cb684 100644 --- a/inferred-spans/src/test/java/io/opentelemetry/contrib/inferredspans/internal/SamplingProfilerTest.java +++ b/inferred-spans/src/test/java/io/opentelemetry/contrib/inferredspans/internal/SamplingProfilerTest.java @@ -44,6 +44,7 @@ class SamplingProfilerTest { static { + // Needed to ensure ordering because tests things out of order ProfilingActivationListener.ensureInitialized(); }