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 52764e6e0b9 CAMEL-18557: camel-core - Total counter on ContextMBean is
too high
52764e6e0b9 is described below
commit 52764e6e0b91ccbd740cc905429e9f35b0b65567
Author: Claus Ibsen <[email protected]>
AuthorDate: Mon Sep 26 19:07:33 2022 +0200
CAMEL-18557: camel-core - Total counter on ContextMBean is too high
---
.../main/java/org/apache/camel/spi/UnitOfWork.java | 13 ++++
.../camel/impl/engine/DefaultUnitOfWork.java | 5 ++
.../management/mbean/ManagedCamelContext.java | 53 ++++++++++++++
.../ManagedCamelContextTotalCounterTest.java | 85 ++++++++++++++++++++++
.../ROOT/pages/camel-3x-upgrade-guide-3_19.adoc | 8 ++
5 files changed, 164 insertions(+)
diff --git a/core/camel-api/src/main/java/org/apache/camel/spi/UnitOfWork.java
b/core/camel-api/src/main/java/org/apache/camel/spi/UnitOfWork.java
index e2f25fa1533..b9d28cb530e 100644
--- a/core/camel-api/src/main/java/org/apache/camel/spi/UnitOfWork.java
+++ b/core/camel-api/src/main/java/org/apache/camel/spi/UnitOfWork.java
@@ -190,6 +190,19 @@ public interface UnitOfWork {
*/
Route popRoute();
+ /**
+ * Gets the {@link Route} level-of-depth that this {@link UnitOfWork}
currently is being routed through.
+ * <p/>
+ * Notice that an {@link Exchange} can be routed through multiple routes
and thus the level of depth can change over
+ * time.
+ *
+ * If level is 1 then the current route is at the first route (original
route). Maybe be <tt>0</tt> if not routed
+ * through a route currently.
+ *
+ * @return the route level-of-depth
+ */
+ int routeStackLevel();
+
/**
* Whether the unit of work should call the before/after process methods
or not.
*/
diff --git
a/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/DefaultUnitOfWork.java
b/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/DefaultUnitOfWork.java
index 09110b55a89..ea1640933a6 100644
---
a/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/DefaultUnitOfWork.java
+++
b/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/DefaultUnitOfWork.java
@@ -348,6 +348,11 @@ public class DefaultUnitOfWork implements UnitOfWork {
return routes.poll();
}
+ @Override
+ public int routeStackLevel() {
+ return routes.size();
+ }
+
@Override
public boolean isBeforeAfterProcess() {
return false;
diff --git
a/core/camel-management/src/main/java/org/apache/camel/management/mbean/ManagedCamelContext.java
b/core/camel-management/src/main/java/org/apache/camel/management/mbean/ManagedCamelContext.java
index 511fa3fbb72..2d9e1848aa8 100644
---
a/core/camel-management/src/main/java/org/apache/camel/management/mbean/ManagedCamelContext.java
+++
b/core/camel-management/src/main/java/org/apache/camel/management/mbean/ManagedCamelContext.java
@@ -32,6 +32,7 @@ import org.w3c.dom.Document;
import org.apache.camel.CamelContext;
import org.apache.camel.Endpoint;
+import org.apache.camel.Exchange;
import org.apache.camel.ExtendedCamelContext;
import org.apache.camel.ManagementStatisticsLevel;
import org.apache.camel.Producer;
@@ -52,6 +53,7 @@ import org.apache.camel.model.RoutesDefinition;
import org.apache.camel.model.rest.RestDefinition;
import org.apache.camel.model.rest.RestsDefinition;
import org.apache.camel.spi.ManagementStrategy;
+import org.apache.camel.spi.UnitOfWork;
@ManagedResource(description = "Managed CamelContext")
public class ManagedCamelContext extends ManagedPerformanceCounter implements
TimerListener, ManagedCamelContextMBean {
@@ -74,6 +76,57 @@ public class ManagedCamelContext extends
ManagedPerformanceCounter implements Ti
setStatisticsEnabled(enabled);
}
+ @Override
+ public void completedExchange(Exchange exchange, long time) {
+ // the camel-context mbean is triggered for every route mbean
+ // so we must only trigger on the root level, otherwise the context
mbean
+ // total counter will be incorrect. For example if an exchange is
routed via 3 routes
+ // we should only count this as 1 instead of 3.
+ UnitOfWork uow = exchange.getUnitOfWork();
+ if (uow != null) {
+ int level = uow.routeStackLevel();
+ if (level <= 1) {
+ super.completedExchange(exchange, time);
+ }
+ } else {
+ super.completedExchange(exchange, time);
+ }
+ }
+
+ @Override
+ public void failedExchange(Exchange exchange) {
+ // the camel-context mbean is triggered for every route mbean
+ // so we must only trigger on the root level, otherwise the context
mbean
+ // total counter will be incorrect. For example if an exchange is
routed via 3 routes
+ // we should only count this as 1 instead of 3.
+ UnitOfWork uow = exchange.getUnitOfWork();
+ if (uow != null) {
+ int level = uow.routeStackLevel();
+ if (level <= 1) {
+ super.failedExchange(exchange);
+ }
+ } else {
+ super.failedExchange(exchange);
+ }
+ }
+
+ @Override
+ public void processExchange(Exchange exchange, String type) {
+ // the camel-context mbean is triggered for every route mbean
+ // so we must only trigger on the root level, otherwise the context
mbean
+ // total counter will be incorrect. For example if an exchange is
routed via 3 routes
+ // we should only count this as 1 instead of 3.
+ UnitOfWork uow = exchange.getUnitOfWork();
+ if (uow != null) {
+ int level = uow.routeStackLevel();
+ if (level <= 1) {
+ super.processExchange(exchange, type);
+ }
+ } else {
+ super.processExchange(exchange, type);
+ }
+ }
+
public CamelContext getContext() {
return context;
}
diff --git
a/core/camel-management/src/test/java/org/apache/camel/management/ManagedCamelContextTotalCounterTest.java
b/core/camel-management/src/test/java/org/apache/camel/management/ManagedCamelContextTotalCounterTest.java
new file mode 100644
index 00000000000..5fb6b28cd25
--- /dev/null
+++
b/core/camel-management/src/test/java/org/apache/camel/management/ManagedCamelContextTotalCounterTest.java
@@ -0,0 +1,85 @@
+/*
+ * 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 javax.management.MBeanServer;
+import javax.management.ObjectName;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.impl.engine.ExplicitCamelContextNameStrategy;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.condition.DisabledOnOs;
+import org.junit.jupiter.api.condition.OS;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+@DisabledOnOs(OS.AIX)
+public class ManagedCamelContextTotalCounterTest extends ManagementTestSupport
{
+
+ @Override
+ protected CamelContext createCamelContext() throws Exception {
+ CamelContext context = super.createCamelContext();
+ // to force a different management name than the camel id
+ context.getManagementNameStrategy().setNamePattern("20-#name#");
+ context.setNameStrategy(new
ExplicitCamelContextNameStrategy("my-camel-context"));
+ return context;
+ }
+
+ @Test
+ public void testContextTotalCounter() throws Exception {
+ template.sendBody("direct:a", "Hello World");
+
+ MBeanServer mbeanServer = getMBeanServer();
+ ObjectName on = getContextObjectName();
+
+ assertTrue(mbeanServer.isRegistered(on), "Should be registered");
+ String name = (String) mbeanServer.getAttribute(on, "CamelId");
+ assertEquals("my-camel-context", name);
+
+ String managementName = (String) mbeanServer.getAttribute(on,
"ManagementName");
+ assertEquals("20-my-camel-context", managementName);
+
+ Integer total = (Integer) mbeanServer.getAttribute(on, "TotalRoutes");
+ assertEquals(3, total.intValue());
+
+ // 3 routes but only 1 exchange completed
+ Long ec = (Long) mbeanServer.getAttribute(on, "ExchangesCompleted");
+ assertEquals(1, ec.intValue());
+ }
+
+ @Override
+ protected RouteBuilder createRouteBuilder() throws Exception {
+ return new RouteBuilder() {
+ @Override
+ public void configure() throws Exception {
+ from("direct:a")
+ .to("log:a")
+ .to("direct:b");
+
+ from("direct:b")
+ .to("log:b")
+ .to("direct:c");
+
+ from("direct:c")
+ .to("log:c");
+ }
+ };
+ }
+
+}
diff --git
a/docs/user-manual/modules/ROOT/pages/camel-3x-upgrade-guide-3_19.adoc
b/docs/user-manual/modules/ROOT/pages/camel-3x-upgrade-guide-3_19.adoc
index 90a14b93ca3..6ccb2fe316a 100644
--- a/docs/user-manual/modules/ROOT/pages/camel-3x-upgrade-guide-3_19.adoc
+++ b/docs/user-manual/modules/ROOT/pages/camel-3x-upgrade-guide-3_19.adoc
@@ -12,6 +12,14 @@ Added `addClassLoader` method to
`org.apache.camel.spi.ClassResolver`.
The default TLS protocol is changed from `TLSv1.2` to `TLSv1.3` in Camel JSSE
support.
+=== camel-management
+
+The context MBean (`ManagedCamelContextMBean`) total counter is changed to
count only once
+while an _exchange_ is being routed through multiple routes. Previously the
counter was
+a total aggregation of all the routes the _exchange_ was processed. For
example if an _exchange_
+is routed via A, B and C; then previously the total counter was +3 (+1 for
route A, +1 for route B, +1 for route C).
+This is now corrected so the total is +1 on the context MBean.
+
=== camel-main
The option `camel.main.eager-classloading` has been removed.