This is an automated email from the ASF dual-hosted git repository. davsclaus pushed a commit to branch CAMEL-23615 in repository https://gitbox.apache.org/repos/asf/camel.git
commit 9b76cad3e8227356e7b93fd3dccc250c990354d3 Author: Claus Ibsen <[email protected]> AuthorDate: Tue May 26 12:59:38 2026 +0200 CAMEL-23615: Add getLastExchangeFailureHandledTimestamp() to management API and dev consoles Co-Authored-By: Claude Opus 4.6 <[email protected]> --- .../camel/impl/console/ConsumerDevConsole.java | 4 ++ .../camel/impl/console/ContextDevConsole.java | 9 +++ .../camel/impl/console/ProcessorDevConsole.java | 9 +++ .../apache/camel/impl/console/RouteDevConsole.java | 9 +++ .../camel/impl/console/RouteGroupDevConsole.java | 9 +++ .../mbean/ManagedPerformanceCounterMBean.java | 3 + .../mbean/ManagedPerformanceCounter.java | 13 ++++ .../ManagedFailureHandledTimestampTest.java | 81 ++++++++++++++++++++++ 8 files changed, 137 insertions(+) diff --git a/core/camel-console/src/main/java/org/apache/camel/impl/console/ConsumerDevConsole.java b/core/camel-console/src/main/java/org/apache/camel/impl/console/ConsumerDevConsole.java index bdba7ca057b1..7c8680a23df2 100644 --- a/core/camel-console/src/main/java/org/apache/camel/impl/console/ConsumerDevConsole.java +++ b/core/camel-console/src/main/java/org/apache/camel/impl/console/ConsumerDevConsole.java @@ -245,6 +245,10 @@ public class ConsumerDevConsole extends AbstractDevConsole { if (last != null) { stats.put("lastCompletedExchangeTimestamp", last.getTime()); } + last = mr.getLastExchangeFailureHandledTimestamp(); + if (last != null) { + stats.put("lastFailureHandledExchangeTimestamp", last.getTime()); + } last = mr.getLastExchangeFailureTimestamp(); if (last != null) { stats.put("lastFailedExchangeTimestamp", last.getTime()); diff --git a/core/camel-console/src/main/java/org/apache/camel/impl/console/ContextDevConsole.java b/core/camel-console/src/main/java/org/apache/camel/impl/console/ContextDevConsole.java index 9e590550b410..af9df21329c8 100644 --- a/core/camel-console/src/main/java/org/apache/camel/impl/console/ContextDevConsole.java +++ b/core/camel-console/src/main/java/org/apache/camel/impl/console/ContextDevConsole.java @@ -111,6 +111,11 @@ public class ContextDevConsole extends AbstractDevConsole { String ago = TimeUtils.printSince(last.getTime()); sb.append(String.format("%n Since Last Completed: %s", ago)); } + last = mb.getLastExchangeFailureHandledTimestamp(); + if (last != null) { + String ago = TimeUtils.printSince(last.getTime()); + sb.append(String.format("%n Since Last Failure Handled: %s", ago)); + } last = mb.getLastExchangeFailureTimestamp(); if (last != null) { String ago = TimeUtils.printSince(last.getTime()); @@ -183,6 +188,10 @@ public class ContextDevConsole extends AbstractDevConsole { if (last != null) { stats.put("lastCompletedExchangeTimestamp", last.getTime()); } + last = mb.getLastExchangeFailureHandledTimestamp(); + if (last != null) { + stats.put("lastFailureHandledExchangeTimestamp", last.getTime()); + } last = mb.getLastExchangeFailureTimestamp(); if (last != null) { stats.put("lastFailedExchangeTimestamp", last.getTime()); diff --git a/core/camel-console/src/main/java/org/apache/camel/impl/console/ProcessorDevConsole.java b/core/camel-console/src/main/java/org/apache/camel/impl/console/ProcessorDevConsole.java index a3306453fad7..b19974090332 100644 --- a/core/camel-console/src/main/java/org/apache/camel/impl/console/ProcessorDevConsole.java +++ b/core/camel-console/src/main/java/org/apache/camel/impl/console/ProcessorDevConsole.java @@ -175,6 +175,11 @@ public class ProcessorDevConsole extends AbstractDevConsole { String ago = TimeUtils.printSince(last.getTime()); sb.append(String.format("%n Since Last Completed: %s", ago)); } + last = mp.getLastExchangeFailureHandledTimestamp(); + if (last != null) { + String ago = TimeUtils.printSince(last.getTime()); + sb.append(String.format("%n Since Last Failure Handled: %s", ago)); + } last = mp.getLastExchangeFailureTimestamp(); if (last != null) { String ago = TimeUtils.printSince(last.getTime()); @@ -346,6 +351,10 @@ public class ProcessorDevConsole extends AbstractDevConsole { if (last != null) { stats.put("lastCompletedExchangeTimestamp", last.getTime()); } + last = mp.getLastExchangeFailureHandledTimestamp(); + if (last != null) { + stats.put("lastFailureHandledExchangeTimestamp", last.getTime()); + } last = mp.getLastExchangeFailureTimestamp(); if (last != null) { stats.put("lastFailedExchangeTimestamp", last.getTime()); diff --git a/core/camel-console/src/main/java/org/apache/camel/impl/console/RouteDevConsole.java b/core/camel-console/src/main/java/org/apache/camel/impl/console/RouteDevConsole.java index f5df4eb4e91f..88df80b03187 100644 --- a/core/camel-console/src/main/java/org/apache/camel/impl/console/RouteDevConsole.java +++ b/core/camel-console/src/main/java/org/apache/camel/impl/console/RouteDevConsole.java @@ -170,6 +170,11 @@ public class RouteDevConsole extends AbstractDevConsole { String ago = TimeUtils.printSince(last.getTime()); sb.append(String.format("%n Since Last Completed: %s", ago)); } + last = mrb.getLastExchangeFailureHandledTimestamp(); + if (last != null) { + String ago = TimeUtils.printSince(last.getTime()); + sb.append(String.format("%n Since Last Failure Handled: %s", ago)); + } last = mrb.getLastExchangeFailureTimestamp(); if (last != null) { String ago = TimeUtils.printSince(last.getTime()); @@ -495,6 +500,10 @@ public class RouteDevConsole extends AbstractDevConsole { if (last != null) { stats.put("lastCompletedExchangeTimestamp", last.getTime()); } + last = mrb.getLastExchangeFailureHandledTimestamp(); + if (last != null) { + stats.put("lastFailureHandledExchangeTimestamp", last.getTime()); + } last = mrb.getLastExchangeFailureTimestamp(); if (last != null) { stats.put("lastFailedExchangeTimestamp", last.getTime()); diff --git a/core/camel-console/src/main/java/org/apache/camel/impl/console/RouteGroupDevConsole.java b/core/camel-console/src/main/java/org/apache/camel/impl/console/RouteGroupDevConsole.java index f0df217590bd..04101fc83c4d 100644 --- a/core/camel-console/src/main/java/org/apache/camel/impl/console/RouteGroupDevConsole.java +++ b/core/camel-console/src/main/java/org/apache/camel/impl/console/RouteGroupDevConsole.java @@ -124,6 +124,11 @@ public class RouteGroupDevConsole extends AbstractDevConsole { String ago = TimeUtils.printSince(last.getTime()); sb.append(String.format("%n Since Last Completed: %s", ago)); } + last = mrg.getLastExchangeFailureHandledTimestamp(); + if (last != null) { + String ago = TimeUtils.printSince(last.getTime()); + sb.append(String.format("%n Since Last Failure Handled: %s", ago)); + } last = mrg.getLastExchangeFailureTimestamp(); if (last != null) { String ago = TimeUtils.printSince(last.getTime()); @@ -191,6 +196,10 @@ public class RouteGroupDevConsole extends AbstractDevConsole { if (last != null) { stats.put("lastCompletedExchangeTimestamp", last.getTime()); } + last = mrg.getLastExchangeFailureHandledTimestamp(); + if (last != null) { + stats.put("lastFailureHandledExchangeTimestamp", last.getTime()); + } last = mrg.getLastExchangeFailureTimestamp(); if (last != null) { stats.put("lastFailedExchangeTimestamp", last.getTime()); diff --git a/core/camel-management-api/src/main/java/org/apache/camel/api/management/mbean/ManagedPerformanceCounterMBean.java b/core/camel-management-api/src/main/java/org/apache/camel/api/management/mbean/ManagedPerformanceCounterMBean.java index b7b1f83d72ad..53a38810e07c 100644 --- a/core/camel-management-api/src/main/java/org/apache/camel/api/management/mbean/ManagedPerformanceCounterMBean.java +++ b/core/camel-management-api/src/main/java/org/apache/camel/api/management/mbean/ManagedPerformanceCounterMBean.java @@ -78,6 +78,9 @@ public interface ManagedPerformanceCounterMBean extends ManagedCounterMBean { @ManagedAttribute(description = "First Exchange Completed ExchangeId") String getFirstExchangeCompletedExchangeId(); + @ManagedAttribute(description = "Last Exchange Failure Handled Timestamp") + Date getLastExchangeFailureHandledTimestamp(); + @ManagedAttribute(description = "Last Exchange Failed Timestamp") Date getLastExchangeFailureTimestamp(); diff --git a/core/camel-management/src/main/java/org/apache/camel/management/mbean/ManagedPerformanceCounter.java b/core/camel-management/src/main/java/org/apache/camel/management/mbean/ManagedPerformanceCounter.java index f60378d8a5f6..150434e4ec30 100644 --- a/core/camel-management/src/main/java/org/apache/camel/management/mbean/ManagedPerformanceCounter.java +++ b/core/camel-management/src/main/java/org/apache/camel/management/mbean/ManagedPerformanceCounter.java @@ -53,6 +53,7 @@ public abstract class ManagedPerformanceCounter extends ManagedCounter private Statistic lastExchangeCreatedTimestamp; private Statistic lastExchangeCompletedTimestamp; private String lastExchangeCompletedExchangeId; + private Statistic lastExchangeFailureHandledTimestamp; private Statistic lastExchangeFailureTimestamp; private String lastExchangeFailureExchangeId; private boolean statisticsEnabled = true; @@ -79,6 +80,7 @@ public abstract class ManagedPerformanceCounter extends ManagedCounter this.firstExchangeFailureTimestamp = new StatisticValue(); this.lastExchangeCreatedTimestamp = new StatisticValue(); this.lastExchangeCompletedTimestamp = new StatisticValue(); + this.lastExchangeFailureHandledTimestamp = new StatisticValue(); this.lastExchangeFailureTimestamp = new StatisticValue(); } @@ -104,6 +106,7 @@ public abstract class ManagedPerformanceCounter extends ManagedCounter lastExchangeCreatedTimestamp.reset(); lastExchangeCompletedTimestamp.reset(); lastExchangeCompletedExchangeId = null; + lastExchangeFailureHandledTimestamp.reset(); lastExchangeFailureTimestamp.reset(); lastExchangeFailureExchangeId = null; } @@ -212,6 +215,12 @@ public abstract class ManagedPerformanceCounter extends ManagedCounter return firstExchangeCompletedExchangeId; } + @Override + public Date getLastExchangeFailureHandledTimestamp() { + long value = lastExchangeFailureHandledTimestamp.getValue(); + return value > 0 ? new Date(value) : null; + } + @Override public Date getLastExchangeFailureTimestamp() { long value = lastExchangeFailureTimestamp.getValue(); @@ -261,6 +270,7 @@ public abstract class ManagedPerformanceCounter extends ManagedCounter if (ExchangeHelper.isFailureHandled(exchange)) { failuresHandled.increment(); + lastExchangeFailureHandledTimestamp.updateValue(System.currentTimeMillis()); } if (exchange.isExternalRedelivered()) { externalRedeliveries.increment(); @@ -349,6 +359,8 @@ public abstract class ManagedPerformanceCounter extends ManagedCounter sb.append(String.format(" lastExchangeCompletedTimestamp=\"%s\"", dateAsString(lastExchangeCompletedTimestamp.getValue()))); sb.append(String.format(" lastExchangeCompletedExchangeId=\"%s\"", nullSafe(lastExchangeCompletedExchangeId))); + sb.append(String.format(" lastExchangeFailureHandledTimestamp=\"%s\"", + dateAsString(lastExchangeFailureHandledTimestamp.getValue()))); sb.append(String.format(" lastExchangeFailureTimestamp=\"%s\"", dateAsString(lastExchangeFailureTimestamp.getValue()))); sb.append(String.format(" lastExchangeFailureExchangeId=\"%s\"", nullSafe(lastExchangeFailureExchangeId))); @@ -389,6 +401,7 @@ public abstract class ManagedPerformanceCounter extends ManagedCounter jo.put("lastExchangeCreatedTimestamp", lastExchangeCreatedTimestamp.getValue()); jo.put("lastExchangeCompletedTimestamp", lastExchangeCompletedTimestamp.getValue()); jo.put("lastExchangeCompletedExchangeId", lastExchangeCompletedExchangeId); + jo.put("lastExchangeFailureHandledTimestamp", lastExchangeFailureHandledTimestamp.getValue()); jo.put("lastExchangeFailureTimestamp", lastExchangeFailureTimestamp.getValue()); jo.put("lastExchangeFailureExchangeId", lastExchangeFailureExchangeId); } diff --git a/core/camel-management/src/test/java/org/apache/camel/management/ManagedFailureHandledTimestampTest.java b/core/camel-management/src/test/java/org/apache/camel/management/ManagedFailureHandledTimestampTest.java new file mode 100644 index 000000000000..35c57d66411d --- /dev/null +++ b/core/camel-management/src/test/java/org/apache/camel/management/ManagedFailureHandledTimestampTest.java @@ -0,0 +1,81 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.camel.management; + +import java.util.Date; + +import javax.management.MBeanServer; +import javax.management.ObjectName; + +import org.apache.camel.builder.RouteBuilder; +import org.apache.camel.component.mock.MockEndpoint; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.condition.DisabledOnOs; +import org.junit.jupiter.api.condition.OS; + +import static org.apache.camel.management.DefaultManagementObjectNameStrategy.TYPE_ROUTE; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; + +@DisabledOnOs(OS.AIX) +public class ManagedFailureHandledTimestampTest extends ManagementTestSupport { + + @Test + public void testLastExchangeFailureHandledTimestamp() throws Exception { + MBeanServer mbeanServer = getMBeanServer(); + + MockEndpoint dead = getMockEndpoint("mock:dead"); + dead.expectedMessageCount(1); + + template.sendBody("direct:start", "Hello World"); + + assertMockEndpointsSatisfied(); + + ObjectName on = getCamelObjectName(TYPE_ROUTE, "route1"); + + Long completed = (Long) mbeanServer.getAttribute(on, "ExchangesCompleted"); + assertEquals(1, completed.longValue()); + + Long failed = (Long) mbeanServer.getAttribute(on, "ExchangesFailed"); + assertEquals(0, failed.longValue()); + + Long failuresHandled = (Long) mbeanServer.getAttribute(on, "FailuresHandled"); + assertEquals(1, failuresHandled.longValue()); + + Date handledTs = (Date) mbeanServer.getAttribute(on, "LastExchangeFailureHandledTimestamp"); + assertNotNull(handledTs); + + Date failureTs = (Date) mbeanServer.getAttribute(on, "LastExchangeFailureTimestamp"); + assertNull(failureTs); + } + + @Override + protected RouteBuilder createRouteBuilder() { + return new RouteBuilder() { + @Override + public void configure() { + errorHandler(deadLetterChannel("mock:dead")); + + from("direct:start") + .process(exchange -> { + throw new IllegalArgumentException("Forced"); + }); + } + }; + } +}
