From 7454852bbdba94e78200afeb22b5124cea1327df Mon Sep 17 00:00:00 2001 From: ADITYA-CODE-SOURCE Date: Sat, 2 May 2026 16:56:59 +0530 Subject: [PATCH 1/7] fix: LoggingSpanExporter and LoggingMetricExporter flush() always returns success LoggingSpanExporter.flush() and LoggingMetricExporter.flush() unconditionally return success even if underlying handlers fail. This masks errors from the caller. Fixes #8360 --- .../opentelemetry/exporter/logging/LoggingMetricExporter.java | 2 +- .../io/opentelemetry/exporter/logging/LoggingSpanExporter.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/exporters/logging/src/main/java/io/opentelemetry/exporter/logging/LoggingMetricExporter.java b/exporters/logging/src/main/java/io/opentelemetry/exporter/logging/LoggingMetricExporter.java index 8b7d837330f..a9c39155141 100644 --- a/exporters/logging/src/main/java/io/opentelemetry/exporter/logging/LoggingMetricExporter.java +++ b/exporters/logging/src/main/java/io/opentelemetry/exporter/logging/LoggingMetricExporter.java @@ -92,7 +92,7 @@ public CompletableResultCode flush() { return resultCode.fail(); } } - return resultCode.succeed(); + return resultCode; } @Override diff --git a/exporters/logging/src/main/java/io/opentelemetry/exporter/logging/LoggingSpanExporter.java b/exporters/logging/src/main/java/io/opentelemetry/exporter/logging/LoggingSpanExporter.java index 58c828635c0..46b48044c2f 100644 --- a/exporters/logging/src/main/java/io/opentelemetry/exporter/logging/LoggingSpanExporter.java +++ b/exporters/logging/src/main/java/io/opentelemetry/exporter/logging/LoggingSpanExporter.java @@ -82,7 +82,7 @@ public CompletableResultCode flush() { resultCode.fail(); } } - return resultCode.succeed(); + return resultCode; } @Override From be535cb83be02a77b15566358d5f10609962d695 Mon Sep 17 00:00:00 2001 From: ADITYA-CODE-SOURCE Date: Sat, 2 May 2026 17:17:17 +0530 Subject: [PATCH 2/7] fix: explicitly return Success when flush completes without error --- .../exporter/logging/LoggingMetricExporter.java | 5 ++--- .../opentelemetry/exporter/logging/LoggingSpanExporter.java | 5 ++--- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/exporters/logging/src/main/java/io/opentelemetry/exporter/logging/LoggingMetricExporter.java b/exporters/logging/src/main/java/io/opentelemetry/exporter/logging/LoggingMetricExporter.java index a9c39155141..d5753f8b07d 100644 --- a/exporters/logging/src/main/java/io/opentelemetry/exporter/logging/LoggingMetricExporter.java +++ b/exporters/logging/src/main/java/io/opentelemetry/exporter/logging/LoggingMetricExporter.java @@ -84,15 +84,14 @@ public CompletableResultCode export(Collection metrics) { */ @Override public CompletableResultCode flush() { - CompletableResultCode resultCode = new CompletableResultCode(); for (Handler handler : logger.getHandlers()) { try { handler.flush(); } catch (Throwable t) { - return resultCode.fail(); + return CompletableResultCode.ofFailure(); } } - return resultCode; + return CompletableResultCode.ofSuccess(); } @Override diff --git a/exporters/logging/src/main/java/io/opentelemetry/exporter/logging/LoggingSpanExporter.java b/exporters/logging/src/main/java/io/opentelemetry/exporter/logging/LoggingSpanExporter.java index 46b48044c2f..3a620b91d81 100644 --- a/exporters/logging/src/main/java/io/opentelemetry/exporter/logging/LoggingSpanExporter.java +++ b/exporters/logging/src/main/java/io/opentelemetry/exporter/logging/LoggingSpanExporter.java @@ -74,15 +74,14 @@ public CompletableResultCode export(Collection spans) { */ @Override public CompletableResultCode flush() { - CompletableResultCode resultCode = new CompletableResultCode(); for (Handler handler : logger.getHandlers()) { try { handler.flush(); } catch (Throwable t) { - resultCode.fail(); + return CompletableResultCode.ofFailure(); } } - return resultCode; + return CompletableResultCode.ofSuccess(); } @Override From 7195477d0f6815b725e0b8cc30685877dfaeabf6 Mon Sep 17 00:00:00 2001 From: ADITYA-CODE-SOURCE Date: Sat, 2 May 2026 17:22:38 +0530 Subject: [PATCH 3/7] test: add flush failure coverage for LoggingSpanExporter and LoggingMetricExporter --- .../logging/LoggingMetricExporterTest.java | 18 ++++++++++++++++++ .../logging/LoggingSpanExporterTest.java | 18 ++++++++++++++++++ 2 files changed, 36 insertions(+) diff --git a/exporters/logging/src/test/java/io/opentelemetry/exporter/logging/LoggingMetricExporterTest.java b/exporters/logging/src/test/java/io/opentelemetry/exporter/logging/LoggingMetricExporterTest.java index a3021dc8a61..d0ca016f2dd 100644 --- a/exporters/logging/src/test/java/io/opentelemetry/exporter/logging/LoggingMetricExporterTest.java +++ b/exporters/logging/src/test/java/io/opentelemetry/exporter/logging/LoggingMetricExporterTest.java @@ -25,6 +25,7 @@ import java.util.Collections; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; +import java.util.logging.Handler; import java.util.logging.Logger; import java.util.logging.SimpleFormatter; import java.util.logging.StreamHandler; @@ -101,6 +102,23 @@ public synchronized void flush() { assertThat(flushed.get()).isTrue(); } + @Test + void flush_failure() { + Handler failingHandler = + new StreamHandler(new PrintStream(new ByteArrayOutputStream()), new SimpleFormatter()) { + @Override + public synchronized void flush() { + throw new RuntimeException("Flush failed"); + } + }; + Logger.getLogger(LoggingMetricExporter.class.getName()).addHandler(failingHandler); + try { + assertThat(exporter.flush().isSuccess()).isFalse(); + } finally { + Logger.getLogger(LoggingMetricExporter.class.getName()).removeHandler(failingHandler); + } + } + @Test void shutdown() { assertThat(exporter.shutdown().isSuccess()).isTrue(); diff --git a/exporters/logging/src/test/java/io/opentelemetry/exporter/logging/LoggingSpanExporterTest.java b/exporters/logging/src/test/java/io/opentelemetry/exporter/logging/LoggingSpanExporterTest.java index 0a4c504f39e..59ee5da26d0 100644 --- a/exporters/logging/src/test/java/io/opentelemetry/exporter/logging/LoggingSpanExporterTest.java +++ b/exporters/logging/src/test/java/io/opentelemetry/exporter/logging/LoggingSpanExporterTest.java @@ -31,6 +31,7 @@ import java.util.Collections; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; +import java.util.logging.Handler; import java.util.logging.Logger; import java.util.logging.SimpleFormatter; import java.util.logging.StreamHandler; @@ -139,6 +140,23 @@ public synchronized void flush() { assertThat(flushed.get()).isTrue(); } + @Test + void flush_failure() { + Handler failingHandler = + new StreamHandler(new PrintStream(new ByteArrayOutputStream()), new SimpleFormatter()) { + @Override + public synchronized void flush() { + throw new RuntimeException("Flush failed"); + } + }; + Logger.getLogger(LoggingSpanExporter.class.getName()).addHandler(failingHandler); + try { + assertThat(exporter.flush().isSuccess()).isFalse(); + } finally { + Logger.getLogger(LoggingSpanExporter.class.getName()).removeHandler(failingHandler); + } + } + @Test void shutdown() { assertThat(exporter.shutdown().isSuccess()).isTrue(); From a8a5e54dacaa074dcf4ea31c8d9f56ca2131aae3 Mon Sep 17 00:00:00 2001 From: ADITYA-CODE-SOURCE Date: Thu, 7 May 2026 09:06:16 +0530 Subject: [PATCH 4/7] fix: narrow flush fix to span exporter --- .../exporter/logging/LoggingMetricExporter.java | 5 +++-- .../exporter/logging/LoggingSpanExporter.java | 5 +++-- .../exporter/logging/LoggingMetricExporterTest.java | 10 +++++----- .../exporter/logging/LoggingSpanExporterTest.java | 10 +++++----- 4 files changed, 16 insertions(+), 14 deletions(-) diff --git a/exporters/logging/src/main/java/io/opentelemetry/exporter/logging/LoggingMetricExporter.java b/exporters/logging/src/main/java/io/opentelemetry/exporter/logging/LoggingMetricExporter.java index d5753f8b07d..8b7d837330f 100644 --- a/exporters/logging/src/main/java/io/opentelemetry/exporter/logging/LoggingMetricExporter.java +++ b/exporters/logging/src/main/java/io/opentelemetry/exporter/logging/LoggingMetricExporter.java @@ -84,14 +84,15 @@ public CompletableResultCode export(Collection metrics) { */ @Override public CompletableResultCode flush() { + CompletableResultCode resultCode = new CompletableResultCode(); for (Handler handler : logger.getHandlers()) { try { handler.flush(); } catch (Throwable t) { - return CompletableResultCode.ofFailure(); + return resultCode.fail(); } } - return CompletableResultCode.ofSuccess(); + return resultCode.succeed(); } @Override diff --git a/exporters/logging/src/main/java/io/opentelemetry/exporter/logging/LoggingSpanExporter.java b/exporters/logging/src/main/java/io/opentelemetry/exporter/logging/LoggingSpanExporter.java index 3a620b91d81..7ee2adda978 100644 --- a/exporters/logging/src/main/java/io/opentelemetry/exporter/logging/LoggingSpanExporter.java +++ b/exporters/logging/src/main/java/io/opentelemetry/exporter/logging/LoggingSpanExporter.java @@ -74,14 +74,15 @@ public CompletableResultCode export(Collection spans) { */ @Override public CompletableResultCode flush() { + CompletableResultCode resultCode = new CompletableResultCode(); for (Handler handler : logger.getHandlers()) { try { handler.flush(); } catch (Throwable t) { - return CompletableResultCode.ofFailure(); + return resultCode.fail(); } } - return CompletableResultCode.ofSuccess(); + return resultCode.succeed(); } @Override diff --git a/exporters/logging/src/test/java/io/opentelemetry/exporter/logging/LoggingMetricExporterTest.java b/exporters/logging/src/test/java/io/opentelemetry/exporter/logging/LoggingMetricExporterTest.java index d0ca016f2dd..c0d32e1d5f6 100644 --- a/exporters/logging/src/test/java/io/opentelemetry/exporter/logging/LoggingMetricExporterTest.java +++ b/exporters/logging/src/test/java/io/opentelemetry/exporter/logging/LoggingMetricExporterTest.java @@ -25,7 +25,6 @@ import java.util.Collections; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; -import java.util.logging.Handler; import java.util.logging.Logger; import java.util.logging.SimpleFormatter; import java.util.logging.StreamHandler; @@ -103,19 +102,20 @@ public synchronized void flush() { } @Test - void flush_failure() { - Handler failingHandler = + void flushFailure() { + Logger logger = Logger.getLogger(LoggingMetricExporter.class.getName()); + StreamHandler failingHandler = new StreamHandler(new PrintStream(new ByteArrayOutputStream()), new SimpleFormatter()) { @Override public synchronized void flush() { throw new RuntimeException("Flush failed"); } }; - Logger.getLogger(LoggingMetricExporter.class.getName()).addHandler(failingHandler); + logger.addHandler(failingHandler); try { assertThat(exporter.flush().isSuccess()).isFalse(); } finally { - Logger.getLogger(LoggingMetricExporter.class.getName()).removeHandler(failingHandler); + logger.removeHandler(failingHandler); } } diff --git a/exporters/logging/src/test/java/io/opentelemetry/exporter/logging/LoggingSpanExporterTest.java b/exporters/logging/src/test/java/io/opentelemetry/exporter/logging/LoggingSpanExporterTest.java index 59ee5da26d0..b0bace4caea 100644 --- a/exporters/logging/src/test/java/io/opentelemetry/exporter/logging/LoggingSpanExporterTest.java +++ b/exporters/logging/src/test/java/io/opentelemetry/exporter/logging/LoggingSpanExporterTest.java @@ -31,7 +31,6 @@ import java.util.Collections; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; -import java.util.logging.Handler; import java.util.logging.Logger; import java.util.logging.SimpleFormatter; import java.util.logging.StreamHandler; @@ -141,19 +140,20 @@ public synchronized void flush() { } @Test - void flush_failure() { - Handler failingHandler = + void flushFailure() { + Logger logger = Logger.getLogger(LoggingSpanExporter.class.getName()); + StreamHandler failingHandler = new StreamHandler(new PrintStream(new ByteArrayOutputStream()), new SimpleFormatter()) { @Override public synchronized void flush() { throw new RuntimeException("Flush failed"); } }; - Logger.getLogger(LoggingSpanExporter.class.getName()).addHandler(failingHandler); + logger.addHandler(failingHandler); try { assertThat(exporter.flush().isSuccess()).isFalse(); } finally { - Logger.getLogger(LoggingSpanExporter.class.getName()).removeHandler(failingHandler); + logger.removeHandler(failingHandler); } } From db11577fd4d2c5f32fed6d99b9c2fdc874a0f3b5 Mon Sep 17 00:00:00 2001 From: ADITYA-CODE-SOURCE Date: Thu, 7 May 2026 09:11:09 +0530 Subject: [PATCH 5/7] fix: disable config cache for graal incubating test --- integration-tests/graal-incubating/build.gradle.kts | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/integration-tests/graal-incubating/build.gradle.kts b/integration-tests/graal-incubating/build.gradle.kts index b0a2a29b416..8b5c5f49ed6 100644 --- a/integration-tests/graal-incubating/build.gradle.kts +++ b/integration-tests/graal-incubating/build.gradle.kts @@ -1,4 +1,5 @@ import org.gradle.api.JavaVersion +import org.gradle.api.tasks.testing.Test plugins { id("otel.java-conventions") @@ -45,3 +46,9 @@ graalvmNative { enabled.set(false) } } + +tasks.named("test") { + notCompatibleWithConfigurationCache( + "GraalVM native test agent options are not serializable for this task.", + ) +} From 49a87039473b79993b616bc3c928ccc0ced895b3 Mon Sep 17 00:00:00 2001 From: ADITYA-CODE-SOURCE Date: Thu, 7 May 2026 09:49:56 +0530 Subject: [PATCH 6/7] test: isolate logging exporter flush handlers --- .../logging/LoggingMetricExporterTest.java | 25 +++++++++++-------- .../logging/LoggingSpanExporterTest.java | 25 +++++++++++-------- .../graal-incubating/build.gradle.kts | 8 ------ 3 files changed, 30 insertions(+), 28 deletions(-) diff --git a/exporters/logging/src/test/java/io/opentelemetry/exporter/logging/LoggingMetricExporterTest.java b/exporters/logging/src/test/java/io/opentelemetry/exporter/logging/LoggingMetricExporterTest.java index c0d32e1d5f6..d85fe7528ae 100644 --- a/exporters/logging/src/test/java/io/opentelemetry/exporter/logging/LoggingMetricExporterTest.java +++ b/exporters/logging/src/test/java/io/opentelemetry/exporter/logging/LoggingMetricExporterTest.java @@ -89,16 +89,21 @@ void export() { @Test void flush() { AtomicBoolean flushed = new AtomicBoolean(false); - Logger.getLogger(LoggingMetricExporter.class.getName()) - .addHandler( - new StreamHandler(new PrintStream(new ByteArrayOutputStream()), new SimpleFormatter()) { - @Override - public synchronized void flush() { - flushed.set(true); - } - }); - exporter.flush(); - assertThat(flushed.get()).isTrue(); + Logger logger = Logger.getLogger(LoggingMetricExporter.class.getName()); + StreamHandler handler = + new StreamHandler(new PrintStream(new ByteArrayOutputStream()), new SimpleFormatter()) { + @Override + public synchronized void flush() { + flushed.set(true); + } + }; + logger.addHandler(handler); + try { + exporter.flush(); + assertThat(flushed.get()).isTrue(); + } finally { + logger.removeHandler(handler); + } } @Test diff --git a/exporters/logging/src/test/java/io/opentelemetry/exporter/logging/LoggingSpanExporterTest.java b/exporters/logging/src/test/java/io/opentelemetry/exporter/logging/LoggingSpanExporterTest.java index b0bace4caea..25e28b41632 100644 --- a/exporters/logging/src/test/java/io/opentelemetry/exporter/logging/LoggingSpanExporterTest.java +++ b/exporters/logging/src/test/java/io/opentelemetry/exporter/logging/LoggingSpanExporterTest.java @@ -127,16 +127,21 @@ void export() { @Test void flush() { AtomicBoolean flushed = new AtomicBoolean(false); - Logger.getLogger(LoggingSpanExporter.class.getName()) - .addHandler( - new StreamHandler(new PrintStream(new ByteArrayOutputStream()), new SimpleFormatter()) { - @Override - public synchronized void flush() { - flushed.set(true); - } - }); - exporter.flush(); - assertThat(flushed.get()).isTrue(); + Logger logger = Logger.getLogger(LoggingSpanExporter.class.getName()); + StreamHandler handler = + new StreamHandler(new PrintStream(new ByteArrayOutputStream()), new SimpleFormatter()) { + @Override + public synchronized void flush() { + flushed.set(true); + } + }; + logger.addHandler(handler); + try { + exporter.flush(); + assertThat(flushed.get()).isTrue(); + } finally { + logger.removeHandler(handler); + } } @Test diff --git a/integration-tests/graal-incubating/build.gradle.kts b/integration-tests/graal-incubating/build.gradle.kts index 8b5c5f49ed6..7bbd8dc143a 100644 --- a/integration-tests/graal-incubating/build.gradle.kts +++ b/integration-tests/graal-incubating/build.gradle.kts @@ -1,6 +1,4 @@ import org.gradle.api.JavaVersion -import org.gradle.api.tasks.testing.Test - plugins { id("otel.java-conventions") id("org.graalvm.buildtools.native") @@ -46,9 +44,3 @@ graalvmNative { enabled.set(false) } } - -tasks.named("test") { - notCompatibleWithConfigurationCache( - "GraalVM native test agent options are not serializable for this task.", - ) -} From 0e034abc69ada37ca2e01fa5e165a93b74039802 Mon Sep 17 00:00:00 2001 From: ADITYA-CODE-SOURCE Date: Thu, 7 May 2026 20:53:21 +0530 Subject: [PATCH 7/7] chore: restore graal incubating formatting --- integration-tests/graal-incubating/build.gradle.kts | 1 + 1 file changed, 1 insertion(+) diff --git a/integration-tests/graal-incubating/build.gradle.kts b/integration-tests/graal-incubating/build.gradle.kts index 7bbd8dc143a..b0a2a29b416 100644 --- a/integration-tests/graal-incubating/build.gradle.kts +++ b/integration-tests/graal-incubating/build.gradle.kts @@ -1,4 +1,5 @@ import org.gradle.api.JavaVersion + plugins { id("otel.java-conventions") id("org.graalvm.buildtools.native")