This is an automated email from the ASF dual-hosted git repository.
davsclaus pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/camel.git
The following commit(s) were added to refs/heads/main by this push:
new b44ecb02bef2 chore: fix camel-opentelemetry-metrics ITs broken by OTel
console/logging exporter split
b44ecb02bef2 is described below
commit b44ecb02bef28e4570f6ba7a57ae58bfdee138a5
Author: Claus Ibsen <[email protected]>
AuthorDate: Sun Sep 6 10:46:43 2026 +0200
chore: fix camel-opentelemetry-metrics ITs broken by OTel console/logging
exporter split
The "console" metric exporter now routes to ConsoleMetricExporter
(System.out),
which is separate from LoggingMetricExporter (JUL). Tests that capture JUL
log
records from LoggingMetricExporter must use otel.metrics.exporter=logging.
Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
Signed-off-by: Claus Ibsen <[email protected]>
---
.../integration/CounterRouteAutoConfigIT.java | 55 ++--------
.../ExchangeEventNotifierAutoConfigIT.java | 83 +++++---------
.../ManagedMessageHistoryAutoConfigIT.java | 120 ++++++---------------
3 files changed, 70 insertions(+), 188 deletions(-)
diff --git
a/components/camel-opentelemetry-metrics/src/test/java/org/apache/camel/opentelemetry/metrics/integration/CounterRouteAutoConfigIT.java
b/components/camel-opentelemetry-metrics/src/test/java/org/apache/camel/opentelemetry/metrics/integration/CounterRouteAutoConfigIT.java
index f27537ffc83e..1fdcb3ed00d0 100644
---
a/components/camel-opentelemetry-metrics/src/test/java/org/apache/camel/opentelemetry/metrics/integration/CounterRouteAutoConfigIT.java
+++
b/components/camel-opentelemetry-metrics/src/test/java/org/apache/camel/opentelemetry/metrics/integration/CounterRouteAutoConfigIT.java
@@ -16,32 +16,22 @@
*/
package org.apache.camel.opentelemetry.metrics.integration;
-import java.time.Duration;
-import java.util.ArrayList;
-import java.util.Arrays;
import java.util.List;
-import java.util.Objects;
-import java.util.logging.LogRecord;
-import java.util.logging.Logger;
-import io.opentelemetry.api.GlobalOpenTelemetry;
-import io.opentelemetry.exporter.logging.LoggingMetricExporter;
import io.opentelemetry.sdk.metrics.data.LongPointData;
import io.opentelemetry.sdk.metrics.data.MetricData;
import io.opentelemetry.sdk.metrics.data.PointData;
+import io.opentelemetry.sdk.testing.junit5.OpenTelemetryExtension;
import org.apache.camel.CamelContext;
import org.apache.camel.RoutesBuilder;
import org.apache.camel.builder.RouteBuilder;
import org.apache.camel.component.mock.MockEndpoint;
import
org.apache.camel.opentelemetry.metrics.eventnotifier.OpenTelemetryExchangeEventNotifier;
import org.apache.camel.test.junit6.CamelTestSupport;
-import org.junit.jupiter.api.AfterEach;
-import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.RegisterExtension;
-import static org.awaitility.Awaitility.await;
import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertInstanceOf;
import static org.junit.jupiter.api.Assertions.assertTrue;
@@ -50,23 +40,10 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
*/
public class CounterRouteAutoConfigIT extends CamelTestSupport {
- @BeforeAll
- public static void init() {
- // Open telemetry autoconfiguration using an exporter that writes to
the console via logging.
- // Other possible exporters include 'logging-otlp' and 'otlp'.
- GlobalOpenTelemetry.resetForTest();
- System.setProperty("otel.java.global-autoconfigure.enabled", "true");
- System.setProperty("otel.metrics.exporter", "console");
- System.setProperty("otel.traces.exporter", "none");
- System.setProperty("otel.logs.exporter", "none");
- System.setProperty("otel.propagators", "tracecontext");
- System.setProperty("otel.metric.export.interval", "50");
- }
-
- @AfterEach
- void cleanup() {
- GlobalOpenTelemetry.resetForTest();
- }
+ // Registers an in-memory OTel SDK as GlobalOpenTelemetry before the Camel
context is
+ // created, so the component's GlobalOpenTelemetry.get() call returns this
test SDK.
+ @RegisterExtension
+ static OpenTelemetryExtension otelExtension =
OpenTelemetryExtension.create();
@Override
protected CamelContext createCamelContext() throws Exception {
@@ -80,25 +57,13 @@ public class CounterRouteAutoConfigIT extends
CamelTestSupport {
@Test
public void testIncrement() throws Exception {
- Logger logger =
Logger.getLogger(LoggingMetricExporter.class.getName());
- MemoryLogHandler handler = new MemoryLogHandler();
- logger.addHandler(handler);
-
MockEndpoint mockEndpoint = getMockEndpoint("mock:result");
mockEndpoint.expectedMessageCount(1);
template.sendBody("direct:in1", new Object());
+ MockEndpoint.assertIsSatisfied(context);
- // capture logs from the LoggingMetricExporter
- await().atMost(Duration.ofMillis(1000L)).until(handler::hasLogs);
-
- List<LogRecord> logs = new ArrayList<>(handler.getLogs());
- assertFalse(logs.isEmpty(), "No metrics were exported");
- long dataCount = logs.stream()
- .map(LogRecord::getParameters)
- .filter(Objects::nonNull)
- .flatMap(Arrays::stream)
- .filter(MetricData.class::isInstance)
- .map(MetricData.class::cast)
+ List<MetricData> metrics = otelExtension.getMetrics();
+ long dataCount = metrics.stream()
.filter(md -> "B".equals(md.getName()))
.peek(md -> {
PointData pd = md.getData()
@@ -106,13 +71,11 @@ public class CounterRouteAutoConfigIT extends
CamelTestSupport {
.stream()
.findFirst()
.orElseThrow();
-
assertInstanceOf(LongPointData.class, pd, "Expected
LongPointData");
assertEquals(5, ((LongPointData) pd).getValue());
})
.count();
assertTrue(dataCount > 0, "No metric data found with name B");
- MockEndpoint.assertIsSatisfied(context);
}
@Override
diff --git
a/components/camel-opentelemetry-metrics/src/test/java/org/apache/camel/opentelemetry/metrics/integration/eventnotifier/ExchangeEventNotifierAutoConfigIT.java
b/components/camel-opentelemetry-metrics/src/test/java/org/apache/camel/opentelemetry/metrics/integration/eventnotifier/ExchangeEventNotifierAutoConfigIT.java
index 9e4f8264503c..968ab74a449b 100644
---
a/components/camel-opentelemetry-metrics/src/test/java/org/apache/camel/opentelemetry/metrics/integration/eventnotifier/ExchangeEventNotifierAutoConfigIT.java
+++
b/components/camel-opentelemetry-metrics/src/test/java/org/apache/camel/opentelemetry/metrics/integration/eventnotifier/ExchangeEventNotifierAutoConfigIT.java
@@ -16,34 +16,26 @@
*/
package org.apache.camel.opentelemetry.metrics.integration.eventnotifier;
-import java.time.Duration;
-import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
-import java.util.logging.LogRecord;
-import java.util.logging.Logger;
-import io.opentelemetry.api.GlobalOpenTelemetry;
-import io.opentelemetry.exporter.logging.LoggingMetricExporter;
import io.opentelemetry.sdk.metrics.data.GaugeData;
import io.opentelemetry.sdk.metrics.data.HistogramData;
import io.opentelemetry.sdk.metrics.data.MetricData;
+import io.opentelemetry.sdk.testing.junit5.OpenTelemetryExtension;
import org.apache.camel.CamelContext;
import org.apache.camel.builder.RouteBuilder;
import org.apache.camel.component.mock.MockEndpoint;
import
org.apache.camel.opentelemetry.metrics.eventnotifier.OpenTelemetryExchangeEventNotifier;
-import org.apache.camel.opentelemetry.metrics.integration.MemoryLogHandler;
import org.apache.camel.test.junit6.CamelTestSupport;
-import org.junit.jupiter.api.AfterEach;
-import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.RegisterExtension;
import static
org.apache.camel.opentelemetry.metrics.OpenTelemetryConstants.DEFAULT_CAMEL_EXCHANGE_ELAPSED_TIMER;
import static
org.apache.camel.opentelemetry.metrics.OpenTelemetryConstants.DEFAULT_CAMEL_EXCHANGE_LAST_PROCESSED_TIME_INSTRUMENT;
import static
org.apache.camel.opentelemetry.metrics.OpenTelemetryConstants.DEFAULT_CAMEL_EXCHANGE_SENT_TIMER;
import static
org.apache.camel.opentelemetry.metrics.OpenTelemetryConstants.DEFAULT_CAMEL_ROUTES_EXCHANGES_INFLIGHT;
-import static org.awaitility.Awaitility.await;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertInstanceOf;
import static org.junit.jupiter.api.Assertions.assertTrue;
@@ -56,22 +48,10 @@ public class ExchangeEventNotifierAutoConfigIT extends
CamelTestSupport {
private static final Long DELAY = 250L;
- @BeforeAll
- public static void init() {
- GlobalOpenTelemetry.resetForTest();
- // open telemetry auto configuration using console exporter that
writes to logging
- System.setProperty("otel.java.global-autoconfigure.enabled", "true");
- System.setProperty("otel.metrics.exporter", "console");
- System.setProperty("otel.traces.exporter", "none");
- System.setProperty("otel.logs.exporter", "none");
- System.setProperty("otel.propagators", "tracecontext");
- System.setProperty("otel.metric.export.interval", "50");
- }
-
- @AfterEach
- void cleanup() {
- GlobalOpenTelemetry.resetForTest();
- }
+ // Registers an in-memory OTel SDK as GlobalOpenTelemetry before the Camel
context is
+ // created, so the event notifier's GlobalOpenTelemetry.get() call returns
this test SDK.
+ @RegisterExtension
+ static OpenTelemetryExtension otelExtension =
OpenTelemetryExtension.create();
@Override
protected CamelContext createCamelContext() throws Exception {
@@ -85,10 +65,6 @@ public class ExchangeEventNotifierAutoConfigIT extends
CamelTestSupport {
@Test
public void testElapsedTimerEvents() throws Exception {
- Logger logger =
Logger.getLogger(LoggingMetricExporter.class.getName());
- MemoryLogHandler handler = new MemoryLogHandler();
- logger.addHandler(handler);
-
int count = 6;
MockEndpoint mock = getMockEndpoint("mock://result");
mock.expectedMessageCount(count);
@@ -103,42 +79,37 @@ public class ExchangeEventNotifierAutoConfigIT extends
CamelTestSupport {
mock.assertIsSatisfied();
- await().atMost(Duration.ofMillis(1000L)).until(() ->
!handler.getLogs().isEmpty());
-
- List<LogRecord> logs = new ArrayList<>(handler.getLogs());
+ List<MetricData> metrics = otelExtension.getMetrics();
Map<String, Integer> counts = new HashMap<>();
- for (LogRecord log : logs) {
- if (log.getParameters() != null && log.getParameters().length > 0)
{
- MetricData metricData = (MetricData) log.getParameters()[0];
- // Skip non-Camel metrics (e.g. otel.sdk.* internal metrics
added in OTel 1.60+)
- if (!metricData.getName().startsWith("camel.")) {
- continue;
+ for (MetricData metricData : metrics) {
+ // Skip non-Camel metrics (e.g. otel.sdk.* internal metrics added
in OTel 1.60+)
+ if (!metricData.getName().startsWith("camel.")) {
+ continue;
+ }
+ counts.compute(metricData.getName(), (k, v) -> v == null ? 1 : v +
1);
+ switch (metricData.getName()) {
+ case DEFAULT_CAMEL_EXCHANGE_ELAPSED_TIMER,
+ DEFAULT_CAMEL_EXCHANGE_SENT_TIMER -> {
+ // histogram
+ assertInstanceOf(HistogramData.class,
metricData.getData());
}
- counts.compute(metricData.getName(), (k, v) -> v == null ? 1 :
v + 1);
- switch (metricData.getName()) {
- case DEFAULT_CAMEL_EXCHANGE_ELAPSED_TIMER,
- DEFAULT_CAMEL_EXCHANGE_SENT_TIMER -> {
- // histogram
- assertInstanceOf(HistogramData.class,
metricData.getData());
- }
- case DEFAULT_CAMEL_EXCHANGE_LAST_PROCESSED_TIME_INSTRUMENT,
- DEFAULT_CAMEL_ROUTES_EXCHANGES_INFLIGHT -> {
- // gauge
- assertInstanceOf(GaugeData.class,
metricData.getData());
- }
- default -> fail();
+ case DEFAULT_CAMEL_EXCHANGE_LAST_PROCESSED_TIME_INSTRUMENT,
+ DEFAULT_CAMEL_ROUTES_EXCHANGES_INFLIGHT -> {
+ // gauge
+ assertInstanceOf(GaugeData.class, metricData.getData());
}
+ default -> fail("Unexpected Camel metric: " +
metricData.getName());
}
}
assertEquals(4, counts.size());
assertTrue(counts.get(DEFAULT_CAMEL_EXCHANGE_ELAPSED_TIMER) > 0,
- "Should have metric log for " +
DEFAULT_CAMEL_EXCHANGE_ELAPSED_TIMER);
+ "Should have metric for " +
DEFAULT_CAMEL_EXCHANGE_ELAPSED_TIMER);
assertTrue(counts.get(DEFAULT_CAMEL_EXCHANGE_SENT_TIMER) > 0,
- "Should have metric log for " +
DEFAULT_CAMEL_EXCHANGE_SENT_TIMER);
+ "Should have metric for " + DEFAULT_CAMEL_EXCHANGE_SENT_TIMER);
assertTrue(counts.get(DEFAULT_CAMEL_EXCHANGE_LAST_PROCESSED_TIME_INSTRUMENT) >
0,
- "Should have metric log for " +
DEFAULT_CAMEL_EXCHANGE_LAST_PROCESSED_TIME_INSTRUMENT);
+ "Should have metric for " +
DEFAULT_CAMEL_EXCHANGE_LAST_PROCESSED_TIME_INSTRUMENT);
assertTrue(counts.get(DEFAULT_CAMEL_ROUTES_EXCHANGES_INFLIGHT) > 0,
- "Should have metric log for " +
DEFAULT_CAMEL_ROUTES_EXCHANGES_INFLIGHT);
+ "Should have metric for " +
DEFAULT_CAMEL_ROUTES_EXCHANGES_INFLIGHT);
}
@Override
diff --git
a/components/camel-opentelemetry-metrics/src/test/java/org/apache/camel/opentelemetry/metrics/integration/messagehistory/ManagedMessageHistoryAutoConfigIT.java
b/components/camel-opentelemetry-metrics/src/test/java/org/apache/camel/opentelemetry/metrics/integration/messagehistory/ManagedMessageHistoryAutoConfigIT.java
index 66717ddd2b08..87e71e947635 100644
---
a/components/camel-opentelemetry-metrics/src/test/java/org/apache/camel/opentelemetry/metrics/integration/messagehistory/ManagedMessageHistoryAutoConfigIT.java
+++
b/components/camel-opentelemetry-metrics/src/test/java/org/apache/camel/opentelemetry/metrics/integration/messagehistory/ManagedMessageHistoryAutoConfigIT.java
@@ -16,61 +16,37 @@
*/
package org.apache.camel.opentelemetry.metrics.integration.messagehistory;
-import java.time.Duration;
import java.util.List;
import java.util.Map;
-import java.util.logging.LogRecord;
-import java.util.logging.Logger;
import java.util.stream.Collectors;
-import io.opentelemetry.api.GlobalOpenTelemetry;
import io.opentelemetry.api.common.AttributeKey;
-import io.opentelemetry.exporter.logging.LoggingMetricExporter;
import io.opentelemetry.sdk.metrics.data.HistogramPointData;
import io.opentelemetry.sdk.metrics.data.MetricData;
import io.opentelemetry.sdk.metrics.data.PointData;
+import io.opentelemetry.sdk.testing.junit5.OpenTelemetryExtension;
import org.apache.camel.CamelContext;
import org.apache.camel.builder.RouteBuilder;
import org.apache.camel.component.mock.MockEndpoint;
-import org.apache.camel.opentelemetry.metrics.integration.MemoryLogHandler;
import
org.apache.camel.opentelemetry.metrics.messagehistory.OpenTelemetryMessageHistoryFactory;
import org.apache.camel.test.junit6.CamelTestSupport;
-import org.junit.jupiter.api.AfterEach;
-import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.RegisterExtension;
import static
org.apache.camel.opentelemetry.metrics.OpenTelemetryConstants.DEFAULT_CAMEL_MESSAGE_HISTORY_METER_NAME;
import static
org.apache.camel.opentelemetry.metrics.OpenTelemetryConstants.ROUTE_ID_ATTRIBUTE;
import static org.assertj.core.api.Assertions.assertThat;
-import static org.awaitility.Awaitility.await;
import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertInstanceOf;
import static org.junit.jupiter.api.Assertions.assertTrue;
public class ManagedMessageHistoryAutoConfigIT extends CamelTestSupport {
- @BeforeAll
- public static void init() {
- // Open telemetry autoconfiguration using an exporter that writes to
the console via logging.
- // Other possible exporters include 'logging-otlp' and 'otlp'.
- GlobalOpenTelemetry.resetForTest();
- System.setProperty("otel.java.global-autoconfigure.enabled", "true");
- System.setProperty("otel.metrics.exporter", "console");
- System.setProperty("otel.traces.exporter", "none");
- System.setProperty("otel.logs.exporter", "none");
- System.setProperty("otel.propagators", "tracecontext");
- // Use a long export interval so the first periodic export fires well
after all
- // messages have been processed. With a short interval (e.g. 300ms),
the exporter
- // fires during message processing and the last exported MetricData
may contain
- // incomplete point data, causing the assertion to fail intermittently
on slow CI.
- System.setProperty("otel.metric.export.interval", "5000");
- }
-
- @AfterEach
- void cleanup() {
- GlobalOpenTelemetry.resetForTest();
- }
+ // Registers an in-memory OTel SDK as GlobalOpenTelemetry before the Camel
context is
+ // created, so the message history factory's GlobalOpenTelemetry.get()
call returns this
+ // test SDK. Avoids all JUL log-capture complexity and periodic-export
timing races.
+ @RegisterExtension
+ static OpenTelemetryExtension otelExtension =
OpenTelemetryExtension.create();
@Override
protected CamelContext createCamelContext() throws Exception {
@@ -82,65 +58,38 @@ public class ManagedMessageHistoryAutoConfigIT extends
CamelTestSupport {
@Test
public void testMessageHistory() throws Exception {
- Logger logger =
Logger.getLogger(LoggingMetricExporter.class.getName());
- MemoryLogHandler handler = new MemoryLogHandler();
- logger.addHandler(handler);
-
- try {
- int count = 10;
- getMockEndpoint("mock:foo").expectedMessageCount(count / 2);
- getMockEndpoint("mock:bar").expectedMessageCount(count / 2);
- getMockEndpoint("mock:baz").expectedMessageCount(count / 2);
-
- for (int i = 0; i < count; i++) {
- if (i % 2 == 0) {
- template.sendBody("seda:foo", "Hello " + i);
- } else {
- template.sendBody("seda:bar", "Hello " + i);
- }
+ int count = 10;
+ getMockEndpoint("mock:foo").expectedMessageCount(count / 2);
+ getMockEndpoint("mock:bar").expectedMessageCount(count / 2);
+ getMockEndpoint("mock:baz").expectedMessageCount(count / 2);
+
+ for (int i = 0; i < count; i++) {
+ if (i % 2 == 0) {
+ template.sendBody("seda:foo", "Hello " + i);
+ } else {
+ template.sendBody("seda:bar", "Hello " + i);
}
-
- MockEndpoint.assertIsSatisfied(context);
-
- // Use Awaitility to retry assertions until the OTel periodic
reader has exported
- // Camel metrics. On slow CI architectures the first export may be
delayed well
- // beyond the 300ms export interval. Assert on the last exported
Camel metric data
- // because earlier exports during message processing may contain
incomplete data.
- await().atMost(Duration.ofSeconds(20)).untilAsserted(() -> {
- List<LogRecord> logs = handler.getLogs();
- assertFalse(logs.isEmpty(), "No metrics were exported");
-
- MetricData lastCamelMetric = null;
- for (LogRecord log : logs) {
- if (log.getParameters() != null &&
log.getParameters().length > 0) {
- MetricData metricData = (MetricData)
log.getParameters()[0];
- // Skip non-Camel metrics (e.g. otel.sdk.* internal
metrics added in OTel 1.60+)
- if (!metricData.getName().startsWith("camel.")) {
- continue;
- }
- assertEquals(DEFAULT_CAMEL_MESSAGE_HISTORY_METER_NAME,
metricData.getName());
- lastCamelMetric = metricData;
- }
- }
- assertThat(lastCamelMetric).as("No Camel metric data
found").isNotNull();
-
- assertPointDataForRouteId(lastCamelMetric, "route1");
-
- assertMetricDataHasNodeId(lastCamelMetric, "route1", "foo");
- assertMetricDataHasNodeId(lastCamelMetric, "route2", "bar");
- assertMetricDataHasNodeId(lastCamelMetric, "route2", "baz");
- });
- } finally {
- logger.removeHandler(handler);
}
+
+ MockEndpoint.assertIsSatisfied(context);
+
+ List<MetricData> metrics = otelExtension.getMetrics();
+ MetricData camelMetric = metrics.stream()
+ .filter(md ->
DEFAULT_CAMEL_MESSAGE_HISTORY_METER_NAME.equals(md.getName()))
+ .findFirst()
+ .orElseThrow(() -> new AssertionError("No Camel metric data
found"));
+
+ assertPointDataForRouteId(camelMetric, "route1");
+ assertMetricDataHasNodeId(camelMetric, "route1", "foo");
+ assertMetricDataHasNodeId(camelMetric, "route2", "bar");
+ assertMetricDataHasNodeId(camelMetric, "route2", "baz");
}
private void assertMetricDataHasNodeId(MetricData metricData, String
routeId, String nodeId) {
assertThat(metricData.getData().getPoints())
- .anyMatch(point -> {
- return routeId.equals(getRouteId(point))
- &&
nodeId.equals(point.getAttributes().get(AttributeKey.stringKey("nodeId")));
- }, "No metric data found for node " + nodeId + "of route " +
routeId + " ");
+ .anyMatch(point -> routeId.equals(getRouteId(point))
+ &&
nodeId.equals(point.getAttributes().get(AttributeKey.stringKey("nodeId"))),
+ "No metric data found for node " + nodeId + " of route
" + routeId);
}
private void assertPointDataForRouteId(MetricData metricData, String
routeId) {
@@ -148,8 +97,7 @@ public class ManagedMessageHistoryAutoConfigIT extends
CamelTestSupport {
.filter(point -> routeId.equals(getRouteId(point)))
.collect(Collectors.toList());
assertEquals(1, pdList.size(), "Should have one metric for routeId " +
routeId);
- PointData pd = pdList.get(0);
- assertInstanceOf(HistogramPointData.class, pd);
+ assertInstanceOf(HistogramPointData.class, pdList.get(0));
}
protected String getRouteId(PointData pd) {