This is an automated email from the ASF dual-hosted git repository. davsclaus pushed a commit to branch CAMEL-23533-enrich in repository https://gitbox.apache.org/repos/asf/camel.git
commit 693bb332a75ab48c20d63698a9e0be97b2f15b86 Author: Claus Ibsen <[email protected]> AuthorDate: Wed May 27 13:32:40 2026 +0200 CAMEL-23533: ErrorRegistry - enrich captured errors with additional context Co-Authored-By: Claude Opus 4.6 <[email protected]> --- .../apache/camel/spi/BacklogErrorEventMessage.java | 31 +++++++++++ .../camel/impl/engine/DefaultErrorRegistry.java | 64 +++++++++++++++++++++- .../org/apache/camel/impl/ErrorRegistryTest.java | 6 ++ .../api/management/mbean/CamelOpenMBeanTypes.java | 11 +++- .../management/mbean/ManagedErrorRegistry.java | 8 ++- 5 files changed, 114 insertions(+), 6 deletions(-) diff --git a/core/camel-api/src/main/java/org/apache/camel/spi/BacklogErrorEventMessage.java b/core/camel-api/src/main/java/org/apache/camel/spi/BacklogErrorEventMessage.java index 0418c1d15e65..f7d64d643e69 100644 --- a/core/camel-api/src/main/java/org/apache/camel/spi/BacklogErrorEventMessage.java +++ b/core/camel-api/src/main/java/org/apache/camel/spi/BacklogErrorEventMessage.java @@ -34,6 +34,37 @@ public interface BacklogErrorEventMessage extends BacklogEventMessage { @Nullable String getRouteGroup(); + /** + * The id of the Step EIP the exchange was inside when the error occurred, or {@code null} if the exchange was not + * inside a Step EIP. + * + * @since 4.21 + */ + @Nullable + String getStepId(); + + /** + * The URI of the route's consumer (from) endpoint where the exchange originated. + * + * @since 4.21 + */ + @Nullable + String getFromEndpointUri(); + + /** + * The uptime of the route (in milliseconds) at the time the error was captured. + * + * @since 4.21 + */ + long getRouteUptime(); + + /** + * The elapsed processing time of the exchange (in milliseconds) from creation until the error was captured. + * + * @since 4.21 + */ + long getElapsed(); + /** * The actual exception that caused the error. This is the live {@link Throwable} instance, not a serialized copy. */ diff --git a/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/DefaultErrorRegistry.java b/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/DefaultErrorRegistry.java index d362482d0ffd..19f88187c31a 100644 --- a/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/DefaultErrorRegistry.java +++ b/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/DefaultErrorRegistry.java @@ -126,6 +126,27 @@ public class DefaultErrorRegistry extends EventNotifierSupport implements ErrorR String toNode = exchange.getExchangeExtension().getHistoryNodeId(); String location = exchange.getExchangeExtension().getHistoryNodeSource(); + // capture step id (set by Step EIP) + String stepId = exchange.getProperty(ExchangePropertyKey.STEP_ID, String.class); + + // capture from endpoint URI + String fromEndpointUri = null; + if (exchange.getFromEndpoint() != null) { + fromEndpointUri = exchange.getFromEndpoint().getEndpointUri(); + } + + // capture route uptime + long routeUptime = 0; + if (routeId != null) { + org.apache.camel.Route r = exchange.getContext().getRoute(routeId); + if (r != null) { + routeUptime = r.getUptimeMillis(); + } + } + + // capture exchange elapsed time + long elapsed = exchange.getClock().elapsed(); + // capture exchange data snapshot JsonObject data = MessageHelper.dumpAsJSonObject( exchange.getMessage(), @@ -140,7 +161,8 @@ public class DefaultErrorRegistry extends EventNotifierSupport implements ErrorR DefaultBacklogErrorEventMessage entry = new DefaultBacklogErrorEventMessage( uid, timestamp, location, routeId, fromRouteId, routeGroup, exchangeId, - endpointUri, toNode, threadName, data, exception, handled, messageHistory); + endpointUri, toNode, stepId, fromEndpointUri, routeUptime, elapsed, + threadName, data, exception, handled, messageHistory); entries.addFirst(entry); evict(); @@ -375,6 +397,10 @@ public class DefaultErrorRegistry extends EventNotifierSupport implements ErrorR private final String exchangeId; private final String endpointUri; private final String toNode; + private final String stepId; + private final String fromEndpointUri; + private final long routeUptime; + private final long elapsed; private final String threadName; private final JsonObject data; private final Throwable exception; @@ -387,7 +413,9 @@ public class DefaultErrorRegistry extends EventNotifierSupport implements ErrorR DefaultBacklogErrorEventMessage( long uid, long timestamp, String location, String routeId, String fromRouteId, String routeGroup, - String exchangeId, String endpointUri, String toNode, String threadName, + String exchangeId, String endpointUri, String toNode, + String stepId, String fromEndpointUri, long routeUptime, long elapsed, + String threadName, JsonObject data, Throwable exception, boolean handled, String[] messageHistory) { this.uid = uid; this.timestamp = timestamp; @@ -398,6 +426,10 @@ public class DefaultErrorRegistry extends EventNotifierSupport implements ErrorR this.exchangeId = exchangeId; this.endpointUri = endpointUri; this.toNode = toNode; + this.stepId = stepId; + this.fromEndpointUri = fromEndpointUri; + this.routeUptime = routeUptime; + this.elapsed = elapsed; this.threadName = threadName; this.data = data; this.exception = exception; @@ -450,6 +482,26 @@ public class DefaultErrorRegistry extends EventNotifierSupport implements ErrorR return toNode; } + @Override + public String getStepId() { + return stepId; + } + + @Override + public String getFromEndpointUri() { + return fromEndpointUri; + } + + @Override + public long getRouteUptime() { + return routeUptime; + } + + @Override + public long getElapsed() { + return elapsed; + } + @Override public String getProcessingThreadName() { return threadName; @@ -537,6 +589,14 @@ public class DefaultErrorRegistry extends EventNotifierSupport implements ErrorR if (toNode != null) { jo.put("nodeId", toNode); } + if (stepId != null) { + jo.put("stepId", stepId); + } + if (fromEndpointUri != null) { + jo.put("fromEndpointUri", fromEndpointUri); + } + jo.put("routeUptime", routeUptime); + jo.put("elapsed", elapsed); jo.put("threadName", threadName); jo.put("handled", handled); // message data diff --git a/core/camel-core/src/test/java/org/apache/camel/impl/ErrorRegistryTest.java b/core/camel-core/src/test/java/org/apache/camel/impl/ErrorRegistryTest.java index 38de8560ac2a..864fe500b059 100644 --- a/core/camel-core/src/test/java/org/apache/camel/impl/ErrorRegistryTest.java +++ b/core/camel-core/src/test/java/org/apache/camel/impl/ErrorRegistryTest.java @@ -65,6 +65,9 @@ public class ErrorRegistryTest extends ContextTestSupport { assertTrue(entry.getException() instanceof IllegalArgumentException); assertTrue(entry.getUid() > 0); assertNotNull(entry.getProcessingThreadName()); + assertEquals("direct://start", entry.getFromEndpointUri()); + assertTrue(entry.getRouteUptime() >= 0, "Route uptime should be non-negative"); + assertTrue(entry.getElapsed() >= 0, "Elapsed time should be non-negative"); } @Test @@ -234,6 +237,9 @@ public class ErrorRegistryTest extends ContextTestSupport { assertNotNull(json.get("exchangeId")); assertNotNull(json.get("exception")); assertNotNull(json.get("message")); + assertEquals("direct://start", json.get("fromEndpointUri")); + assertTrue((long) json.get("routeUptime") >= 0); + assertTrue((long) json.get("elapsed") >= 0); } @Override diff --git a/core/camel-management-api/src/main/java/org/apache/camel/api/management/mbean/CamelOpenMBeanTypes.java b/core/camel-management-api/src/main/java/org/apache/camel/api/management/mbean/CamelOpenMBeanTypes.java index 966217eea084..6264b459c8d9 100644 --- a/core/camel-management-api/src/main/java/org/apache/camel/api/management/mbean/CamelOpenMBeanTypes.java +++ b/core/camel-management-api/src/main/java/org/apache/camel/api/management/mbean/CamelOpenMBeanTypes.java @@ -386,14 +386,19 @@ public final class CamelOpenMBeanTypes { return new CompositeType( "errors", "Errors", new String[] { - "exchangeId", "routeId", "routeGroup", "nodeId", "endpointUri", "timestamp", + "exchangeId", "routeId", "routeGroup", "nodeId", "stepId", + "endpointUri", "fromEndpointUri", "timestamp", + "routeUptime", "elapsed", "handled", "exceptionType", "exceptionMessage" }, new String[] { - "Exchange Id", "Route Id", "Route Group", "Node Id", "Endpoint Uri", "Timestamp", + "Exchange Id", "Route Id", "Route Group", "Node Id", "Step Id", + "Endpoint Uri", "From Endpoint Uri", "Timestamp", + "Route Uptime", "Elapsed", "Handled", "Exception Type", "Exception Message" }, new OpenType[] { SimpleType.STRING, SimpleType.STRING, SimpleType.STRING, SimpleType.STRING, SimpleType.STRING, - SimpleType.STRING, + SimpleType.STRING, SimpleType.STRING, SimpleType.STRING, + SimpleType.LONG, SimpleType.LONG, SimpleType.BOOLEAN, SimpleType.STRING, SimpleType.STRING }); } diff --git a/core/camel-management/src/main/java/org/apache/camel/management/mbean/ManagedErrorRegistry.java b/core/camel-management/src/main/java/org/apache/camel/management/mbean/ManagedErrorRegistry.java index 5f5886b8ba65..3160a08923da 100644 --- a/core/camel-management/src/main/java/org/apache/camel/management/mbean/ManagedErrorRegistry.java +++ b/core/camel-management/src/main/java/org/apache/camel/management/mbean/ManagedErrorRegistry.java @@ -160,15 +160,21 @@ public class ManagedErrorRegistry extends ManagedService implements ManagedError CompositeData data = new CompositeDataSupport( ct, new String[] { - "exchangeId", "routeId", "routeGroup", "nodeId", "endpointUri", "timestamp", + "exchangeId", "routeId", "routeGroup", "nodeId", "stepId", + "endpointUri", "fromEndpointUri", "timestamp", + "routeUptime", "elapsed", "handled", "exceptionType", "exceptionMessage" }, new Object[] { entry.getExchangeId(), entry.getRouteId(), entry.getRouteGroup(), entry.getToNode(), + entry.getStepId(), entry.getEndpointUri(), + entry.getFromEndpointUri(), String.valueOf(entry.getTimestamp()), + entry.getRouteUptime(), + entry.getElapsed(), entry.isHandled(), entry.getExceptionType(), entry.getExceptionMessage() });
