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 8318ebaa3b4 CAMEL-18858: camel-core - Mark route as created by Kamelet so we know this, so we can filter out in tooling and whereelse (kamelet is a blackbox) (#13286) 8318ebaa3b4 is described below commit 8318ebaa3b48c921ef217013487f1d01dcf4306f Author: Claus Ibsen <claus.ib...@gmail.com> AuthorDate: Sun Feb 25 08:59:29 2024 +0100 CAMEL-18858: camel-core - Mark route as created by Kamelet so we know this, so we can filter out in tooling and whereelse (kamelet is a blackbox) (#13286) CAMEL-18858: camel-core - Mark route as created by Kamelet so we know this, so we can filter out in tooling and whereelse (kamelet is a blackbox) --- .../main/camel-main-configuration-metadata.json | 2 + .../apache/camel/catalog/schemas/camel-spring.xsd | 1 + components/camel-kamelet/pom.xml | 5 + .../apache/camel/component/kamelet/Kamelet.java | 2 + .../camel/component/kamelet/KameletProcessor.java | 3 + .../camel/component/kamelet/KameletProducer.java | 14 ++- .../kamelet/ManagedKameletRouteDisabledTest.java | 87 ++++++++++++++ .../kamelet/ManagedKameletRouteEnabledTest.java | 93 +++++++++++++++ .../metrics/routepolicy/MetricsRoutePolicy.java | 24 +++- .../MicrometerExchangeEventNotifier.java | 45 ++++++-- .../MicrometerRouteEventNotifier.java | 20 ++++ .../routepolicy/MicrometerRoutePolicy.java | 19 ++- .../src/main/java/org/apache/camel/Route.java | 16 +++ .../java/org/apache/camel/spi/ManagementAgent.java | 28 +++++ .../main/java/org/apache/camel/spi/UnitOfWork.java | 15 +++ .../camel/impl/engine/AbstractCamelContext.java | 127 ++++++++++++++++++--- .../org/apache/camel/impl/engine/DefaultRoute.java | 15 +++ .../camel/impl/engine/DefaultUnitOfWork.java | 22 ++++ .../camel/impl/console/ConsumerDevConsole.java | 2 +- .../apache/camel/impl/console/RouteDevConsole.java | 5 +- .../camel/impl/console/RouteDumpDevConsole.java | 2 + .../camel/impl/console/SourceDevConsole.java | 2 + .../apache/camel/impl/console/TopDevConsole.java | 3 + .../org/apache/camel/model/RouteDefinition.java | 16 ++- .../org/apache/camel/processor/SendProcessor.java | 3 + .../org/apache/camel/reifier/RouteReifier.java | 2 + .../MainConfigurationPropertiesConfigurer.java | 12 ++ .../camel-main-configuration-metadata.json | 2 + core/camel-main/src/main/docs/main.adoc | 4 +- .../camel/main/DefaultConfigurationConfigurer.java | 4 + .../camel/main/DefaultConfigurationProperties.java | 66 +++++++++++ .../api/management/JmxSystemPropertyKeys.java | 6 + .../api/management/mbean/ManagedRouteMBean.java | 6 + .../camel/management/DefaultManagementAgent.java | 26 +++++ .../management/JmxManagementLifecycleStrategy.java | 9 ++ .../management/mbean/ManagedCamelContext.java | 21 ++-- .../camel/management/mbean/ManagedRoute.java | 10 ++ .../java/org/apache/camel/xml/in/ModelParser.java | 1 + .../java/org/apache/camel/xml/out/ModelWriter.java | 1 + .../org/apache/camel/yaml/out/ModelWriter.java | 1 + .../ROOT/pages/camel-4x-upgrade-guide-4_5.adoc | 21 ++++ docs/user-manual/modules/ROOT/pages/jmx.adoc | 15 ++- 42 files changed, 726 insertions(+), 52 deletions(-) diff --git a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/main/camel-main-configuration-metadata.json b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/main/camel-main-configuration-metadata.json index 127e310a2c6..f1e51f670bf 100644 --- a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/main/camel-main-configuration-metadata.json +++ b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/main/camel-main-configuration-metadata.json @@ -70,6 +70,8 @@ { "name": "camel.main.jmxEnabled", "description": "Enable JMX in your Camel application.", "sourceType": "org.apache.camel.main.DefaultConfigurationProperties", "type": "boolean", "javaType": "boolean", "defaultValue": true }, { "name": "camel.main.jmxManagementMBeansLevel", "description": "Sets the mbeans registration level. The default value is Default.", "sourceType": "org.apache.camel.main.DefaultConfigurationProperties", "type": "object", "javaType": "org.apache.camel.ManagementMBeansLevel", "defaultValue": "Default" }, { "name": "camel.main.jmxManagementNamePattern", "description": "The naming pattern for creating the CamelContext JMX management name. The default pattern is #name#", "sourceType": "org.apache.camel.main.DefaultConfigurationProperties", "type": "string", "javaType": "java.lang.String", "defaultValue": "#name#" }, + { "name": "camel.main.jmxManagementRegisterRoutesCreateByKamelet", "description": "Whether routes created by Kamelets should be registered for JMX management. Enabling this allows to have fine-grained monitoring and management of every route created via Kamelets. This is default disabled as a Kamelet is intended as a component (black-box) and its implementation details as Camel route makes the overall management and monitoring of Camel applications more verbose. During development of [...] + { "name": "camel.main.jmxManagementRegisterRoutesCreateByTemplate", "description": "Whether routes created by route templates (not Kamelets) should be registered for JMX management. Enabling this allows to have fine-grained monitoring and management of every route created via route templates. This is default enabled (unlike Kamelets) as routes created via templates is regarded as standard routes, and should be available for management and monitoring.", "sourceType": "org.apache.camel [...] { "name": "camel.main.jmxManagementStatisticsLevel", "description": "Sets the JMX statistics level, the level can be set to Extended to gather additional information The default value is Default.", "sourceType": "org.apache.camel.main.DefaultConfigurationProperties", "type": "object", "javaType": "org.apache.camel.ManagementStatisticsLevel", "defaultValue": "Default", "enum": [ "Extended", "Default", "RoutesOnly", "Off" ] }, { "name": "camel.main.jmxUpdateRouteEnabled", "description": "Whether to allow updating routes at runtime via JMX using the ManagedRouteMBean. This is disabled by default, but can be enabled for development and troubleshooting purposes, such as updating routes in an existing running Camel via JMX and other tools.", "sourceType": "org.apache.camel.main.DefaultConfigurationProperties", "type": "boolean", "javaType": "boolean", "defaultValue": "false" }, { "name": "camel.main.lightweight", "description": "Configure the context to be lightweight. This will trigger some optimizations and memory reduction options. Lightweight context have some limitations. At this moment, dynamic endpoint destinations are not supported.", "sourceType": "org.apache.camel.main.DefaultConfigurationProperties", "type": "boolean", "javaType": "boolean", "defaultValue": "false" }, diff --git a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/schemas/camel-spring.xsd b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/schemas/camel-spring.xsd index bdf7a264bea..87b01646d3f 100644 --- a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/schemas/camel-spring.xsd +++ b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/schemas/camel-spring.xsd @@ -12258,6 +12258,7 @@ XML. May be null. </xs:documentation> </xs:annotation> </xs:attribute> + <xs:attribute name="kamelet" type="xs:boolean"/> <xs:attribute name="logMask" type="xs:string"> <xs:annotation> <xs:documentation xml:lang="en"> diff --git a/components/camel-kamelet/pom.xml b/components/camel-kamelet/pom.xml index 1fdb9f82918..57b70f9155a 100644 --- a/components/camel-kamelet/pom.xml +++ b/components/camel-kamelet/pom.xml @@ -44,6 +44,11 @@ </dependency> <!-- TESTS --> + <dependency> + <groupId>org.apache.camel</groupId> + <artifactId>camel-management</artifactId> + <scope>test</scope> + </dependency> <dependency> <groupId>org.apache.camel</groupId> <artifactId>camel-xml-jaxb</artifactId> diff --git a/components/camel-kamelet/src/main/java/org/apache/camel/component/kamelet/Kamelet.java b/components/camel-kamelet/src/main/java/org/apache/camel/component/kamelet/Kamelet.java index bda62f27103..3db8c6f8250 100644 --- a/components/camel-kamelet/src/main/java/org/apache/camel/component/kamelet/Kamelet.java +++ b/components/camel-kamelet/src/main/java/org/apache/camel/component/kamelet/Kamelet.java @@ -130,6 +130,8 @@ public final class Kamelet { ObjectHelper.notNull(rid, PARAM_ROUTE_ID); RouteDefinition def = in.asRouteDefinition(); + // mark this as created from a kamelet + def.setKamelet(true); def.setLocation(in.getLocation()); def.setLineNumber(in.getLineNumber()); def.setId(rid); diff --git a/components/camel-kamelet/src/main/java/org/apache/camel/component/kamelet/KameletProcessor.java b/components/camel-kamelet/src/main/java/org/apache/camel/component/kamelet/KameletProcessor.java index be684473f55..9bfab346d8f 100644 --- a/components/camel-kamelet/src/main/java/org/apache/camel/component/kamelet/KameletProcessor.java +++ b/components/camel-kamelet/src/main/java/org/apache/camel/component/kamelet/KameletProcessor.java @@ -123,6 +123,9 @@ public class KameletProcessor extends AsyncProcessorSupport if (producer == null) { producer = (KameletProducer) camelContext.getEndpoint("kamelet://" + name).createAsyncProducer(); } + if (producer != null) { + ((RouteIdAware) producer).setRouteId(getRouteId()); + } ServiceHelper.buildService(processor, producer); // we use the kamelet component (producer) to call the kamelet diff --git a/components/camel-kamelet/src/main/java/org/apache/camel/component/kamelet/KameletProducer.java b/components/camel-kamelet/src/main/java/org/apache/camel/component/kamelet/KameletProducer.java index cc05702c5e8..1e2d2960647 100644 --- a/components/camel-kamelet/src/main/java/org/apache/camel/component/kamelet/KameletProducer.java +++ b/components/camel-kamelet/src/main/java/org/apache/camel/component/kamelet/KameletProducer.java @@ -20,12 +20,13 @@ import org.apache.camel.AsyncCallback; import org.apache.camel.AsyncProcessor; import org.apache.camel.Exchange; import org.apache.camel.Route; +import org.apache.camel.spi.RouteIdAware; import org.apache.camel.support.DefaultAsyncProducer; import org.apache.camel.support.ExchangeHelper; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -final class KameletProducer extends DefaultAsyncProducer { +final class KameletProducer extends DefaultAsyncProducer implements RouteIdAware { private static final Logger LOG = LoggerFactory.getLogger(KameletProducer.class); @@ -38,6 +39,7 @@ final class KameletProducer extends DefaultAsyncProducer { private final boolean block; private final long timeout; private final boolean sink; + private String routeId; public KameletProducer(KameletEndpoint endpoint, String key) { super(endpoint); @@ -124,6 +126,16 @@ final class KameletProducer extends DefaultAsyncProducer { } } + @Override + public String getRouteId() { + return routeId; + } + + @Override + public void setRouteId(String routeId) { + this.routeId = routeId; + } + public String getKey() { return key; } diff --git a/components/camel-kamelet/src/test/java/org/apache/camel/component/kamelet/ManagedKameletRouteDisabledTest.java b/components/camel-kamelet/src/test/java/org/apache/camel/component/kamelet/ManagedKameletRouteDisabledTest.java new file mode 100644 index 00000000000..bfa26bd1990 --- /dev/null +++ b/components/camel-kamelet/src/test/java/org/apache/camel/component/kamelet/ManagedKameletRouteDisabledTest.java @@ -0,0 +1,87 @@ +/* + * 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.component.kamelet; + +import java.util.HashSet; +import java.util.Set; +import java.util.UUID; + +import javax.management.MBeanServer; +import javax.management.ObjectName; + +import org.apache.camel.RoutesBuilder; +import org.apache.camel.builder.RouteBuilder; +import org.apache.camel.test.junit5.CamelTestSupport; +import org.apache.camel.util.StringHelper; +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +public class ManagedKameletRouteDisabledTest extends CamelTestSupport { + + @Override + protected boolean useJmx() { + return true; + } + + protected MBeanServer getMBeanServer() { + return context.getManagementStrategy().getManagementAgent().getMBeanServer(); + } + + @Test + public void testKameletRouteMBeanDisabled() throws Exception { + String body = UUID.randomUUID().toString(); + + assertThat( + fluentTemplate.toF("direct:single").withBody(body).request(String.class)).isEqualTo("a-" + body); + + MBeanServer mbeanServer = getMBeanServer(); + + Set<ObjectName> set = mbeanServer.queryNames(new ObjectName("*:type=routes,*"), null); + assertEquals(1, set.size()); + + Set<String> ids = new HashSet<>(); + for (ObjectName on : set) { + String uri = (String) mbeanServer.getAttribute(on, "EndpointUri"); + String name = StringHelper.before(uri, ":"); + ids.add(name); + } + assertTrue(ids.contains("direct")); + // is disabled by default + assertFalse(ids.contains("kamelet")); + } + + @Override + protected RoutesBuilder createRouteBuilder() throws Exception { + return new RouteBuilder() { + @Override + public void configure() throws Exception { + routeTemplate("echo") + .templateParameter("prefix") + .from("kamelet:source") + .setBody().simple("{{prefix}}-${body}"); + + from("direct:single").routeId("test") + .to("kamelet:echo?prefix=a") + .log("${body}"); + } + }; + } +} diff --git a/components/camel-kamelet/src/test/java/org/apache/camel/component/kamelet/ManagedKameletRouteEnabledTest.java b/components/camel-kamelet/src/test/java/org/apache/camel/component/kamelet/ManagedKameletRouteEnabledTest.java new file mode 100644 index 00000000000..81df1c2d597 --- /dev/null +++ b/components/camel-kamelet/src/test/java/org/apache/camel/component/kamelet/ManagedKameletRouteEnabledTest.java @@ -0,0 +1,93 @@ +/* + * 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.component.kamelet; + +import java.util.HashSet; +import java.util.Set; +import java.util.UUID; + +import javax.management.MBeanServer; +import javax.management.ObjectName; + +import org.apache.camel.CamelContext; +import org.apache.camel.RoutesBuilder; +import org.apache.camel.builder.RouteBuilder; +import org.apache.camel.test.junit5.CamelTestSupport; +import org.apache.camel.util.StringHelper; +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +public class ManagedKameletRouteEnabledTest extends CamelTestSupport { + + @Override + protected boolean useJmx() { + return true; + } + + protected MBeanServer getMBeanServer() { + return context.getManagementStrategy().getManagementAgent().getMBeanServer(); + } + + @Override + protected CamelContext createCamelContext() throws Exception { + CamelContext context = super.createCamelContext(); + context.getManagementStrategy().getManagementAgent().setRegisterRoutesCreateByKamelet(true); + return context; + } + + @Test + public void testKameletRouteMBean() throws Exception { + String body = UUID.randomUUID().toString(); + + assertThat( + fluentTemplate.toF("direct:single").withBody(body).request(String.class)).isEqualTo("a-" + body); + + MBeanServer mbeanServer = getMBeanServer(); + + Set<ObjectName> set = mbeanServer.queryNames(new ObjectName("*:type=routes,*"), null); + assertEquals(2, set.size()); + + Set<String> ids = new HashSet<>(); + for (ObjectName on : set) { + String uri = (String) mbeanServer.getAttribute(on, "EndpointUri"); + String name = StringHelper.before(uri, ":"); + ids.add(name); + } + assertTrue(ids.contains("direct")); + assertTrue(ids.contains("kamelet")); + } + + @Override + protected RoutesBuilder createRouteBuilder() throws Exception { + return new RouteBuilder() { + @Override + public void configure() throws Exception { + routeTemplate("echo") + .templateParameter("prefix") + .from("kamelet:source") + .setBody().simple("{{prefix}}-${body}"); + + from("direct:single").routeId("test") + .to("kamelet:echo?prefix=a") + .log("${body}"); + } + }; + } +} diff --git a/components/camel-metrics/src/main/java/org/apache/camel/component/metrics/routepolicy/MetricsRoutePolicy.java b/components/camel-metrics/src/main/java/org/apache/camel/component/metrics/routepolicy/MetricsRoutePolicy.java index f278fba42c9..17cacae8441 100644 --- a/components/camel-metrics/src/main/java/org/apache/camel/component/metrics/routepolicy/MetricsRoutePolicy.java +++ b/components/camel-metrics/src/main/java/org/apache/camel/component/metrics/routepolicy/MetricsRoutePolicy.java @@ -26,6 +26,7 @@ import org.apache.camel.Exchange; import org.apache.camel.NonManagedService; import org.apache.camel.Route; import org.apache.camel.RuntimeCamelException; +import org.apache.camel.spi.ManagementStrategy; import org.apache.camel.support.RoutePolicySupport; /** @@ -50,6 +51,8 @@ public class MetricsRoutePolicy extends RoutePolicySupport implements NonManaged private MetricsStatistics statistics; private Route route; private String namePattern = String.format("%s.%s.%s", NAME_TOKEN, ROUTE_ID_TOKEN, TYPE_TOKEN); + boolean registerKamelets; + boolean registerTemplates = true; private static final class MetricsStatistics { private final String routeId; @@ -139,6 +142,12 @@ public class MetricsRoutePolicy extends RoutePolicySupport implements NonManaged public void onInit(Route route) { super.onInit(route); + ManagementStrategy ms = route.getCamelContext().getManagementStrategy(); + if (ms != null && ms.getManagementAgent() != null) { + registerKamelets = ms.getManagementAgent().getRegisterRoutesCreateByKamelet(); + registerTemplates = ms.getManagementAgent().getRegisterRoutesCreateByTemplate(); + } + this.route = route; try { registryService = route.getCamelContext().hasService(MetricsRegistryService.class); @@ -156,11 +165,16 @@ public class MetricsRoutePolicy extends RoutePolicySupport implements NonManaged throw RuntimeCamelException.wrapRuntimeCamelException(e); } - // create statistics holder - // for know we record only all the timings of a complete exchange (responses) - // we have in-flight / total statistics already from camel-core - Timer responses = registryService.getMetricsRegistry().timer(createName("responses")); - statistics = new MetricsStatistics(route, responses); + // skip routes that should not be included + boolean skip = (route.isCreatedByKamelet() && !registerKamelets) + || (route.isCreatedByRouteTemplate() && !registerTemplates); + if (!skip) { + // create statistics holder + // for know we record only all the timings of a complete exchange (responses) + // we have in-flight / total statistics already from camel-core + Timer responses = registryService.getMetricsRegistry().timer(createName("responses")); + statistics = new MetricsStatistics(route, responses); + } } private String createName(String type) { diff --git a/components/camel-micrometer/src/main/java/org/apache/camel/component/micrometer/eventnotifier/MicrometerExchangeEventNotifier.java b/components/camel-micrometer/src/main/java/org/apache/camel/component/micrometer/eventnotifier/MicrometerExchangeEventNotifier.java index 61ce90e9526..8dbac32b26f 100644 --- a/components/camel-micrometer/src/main/java/org/apache/camel/component/micrometer/eventnotifier/MicrometerExchangeEventNotifier.java +++ b/components/camel-micrometer/src/main/java/org/apache/camel/component/micrometer/eventnotifier/MicrometerExchangeEventNotifier.java @@ -26,6 +26,7 @@ import io.micrometer.core.instrument.Meter; import io.micrometer.core.instrument.Tags; import io.micrometer.core.instrument.Timer; import org.apache.camel.Exchange; +import org.apache.camel.Route; import org.apache.camel.spi.CamelEvent; import org.apache.camel.spi.CamelEvent.ExchangeCompletedEvent; import org.apache.camel.spi.CamelEvent.ExchangeCreatedEvent; @@ -33,6 +34,8 @@ import org.apache.camel.spi.CamelEvent.ExchangeEvent; import org.apache.camel.spi.CamelEvent.ExchangeFailedEvent; import org.apache.camel.spi.CamelEvent.ExchangeSentEvent; import org.apache.camel.spi.InflightRepository; +import org.apache.camel.spi.ManagementStrategy; +import org.apache.camel.support.ExchangeHelper; import org.apache.camel.support.SimpleEventNotifierSupport; public class MicrometerExchangeEventNotifier extends AbstractMicrometerEventNotifier<ExchangeEvent> { @@ -42,6 +45,8 @@ public class MicrometerExchangeEventNotifier extends AbstractMicrometerEventNoti private Predicate<Exchange> ignoreExchanges = exchange -> false; private MicrometerExchangeEventNotifierNamingStrategy namingStrategy = MicrometerExchangeEventNotifierNamingStrategy.DEFAULT; + boolean registerKamelets; + boolean registerTemplates = true; public MicrometerExchangeEventNotifier() { super(ExchangeEvent.class); @@ -63,6 +68,15 @@ public class MicrometerExchangeEventNotifier extends AbstractMicrometerEventNoti this.namingStrategy = namingStrategy; } + @Override + protected void doInit() throws Exception { + ManagementStrategy ms = getCamelContext().getManagementStrategy(); + if (ms != null && ms.getManagementAgent() != null) { + registerKamelets = ms.getManagementAgent().getRegisterRoutesCreateByKamelet(); + registerTemplates = ms.getManagementAgent().getRegisterRoutesCreateByTemplate(); + } + } + @Override protected void doStart() throws Exception { super.doStart(); @@ -94,14 +108,29 @@ public class MicrometerExchangeEventNotifier extends AbstractMicrometerEventNoti @Override public void notify(CamelEvent eventObject) { - if (!(getIgnoreExchanges().test(((ExchangeEvent) eventObject).getExchange()))) { - handleExchangeEvent((ExchangeEvent) eventObject); - if (eventObject instanceof ExchangeCreatedEvent) { - handleCreatedEvent((ExchangeCreatedEvent) eventObject); - } else if (eventObject instanceof ExchangeSentEvent) { - handleSentEvent((ExchangeSentEvent) eventObject); - } else if (eventObject instanceof ExchangeCompletedEvent || eventObject instanceof ExchangeFailedEvent) { - handleDoneEvent((ExchangeEvent) eventObject); + if (eventObject instanceof ExchangeEvent ee) { + // skip routes that should not be included + boolean skip = false; + String routeId = ExchangeHelper.getAtRouteId(ee.getExchange()); + if (routeId != null) { + Route route = ee.getExchange().getContext().getRoute(routeId); + if (route != null) { + skip = (route.isCreatedByKamelet() && !registerKamelets) + || (route.isCreatedByRouteTemplate() && !registerTemplates); + } + } + if (skip) { + return; + } + if (!(getIgnoreExchanges().test(ee.getExchange()))) { + handleExchangeEvent(ee); + if (eventObject instanceof ExchangeCreatedEvent) { + handleCreatedEvent((ExchangeCreatedEvent) eventObject); + } else if (eventObject instanceof ExchangeSentEvent) { + handleSentEvent((ExchangeSentEvent) eventObject); + } else if (eventObject instanceof ExchangeCompletedEvent || eventObject instanceof ExchangeFailedEvent) { + handleDoneEvent((ExchangeEvent) eventObject); + } } } } diff --git a/components/camel-micrometer/src/main/java/org/apache/camel/component/micrometer/eventnotifier/MicrometerRouteEventNotifier.java b/components/camel-micrometer/src/main/java/org/apache/camel/component/micrometer/eventnotifier/MicrometerRouteEventNotifier.java index 6c638e031ce..04b5cb07266 100644 --- a/components/camel-micrometer/src/main/java/org/apache/camel/component/micrometer/eventnotifier/MicrometerRouteEventNotifier.java +++ b/components/camel-micrometer/src/main/java/org/apache/camel/component/micrometer/eventnotifier/MicrometerRouteEventNotifier.java @@ -26,6 +26,7 @@ import org.apache.camel.spi.CamelEvent.RouteReloadedEvent; import org.apache.camel.spi.CamelEvent.RouteRemovedEvent; import org.apache.camel.spi.CamelEvent.RouteStartedEvent; import org.apache.camel.spi.CamelEvent.RouteStoppedEvent; +import org.apache.camel.spi.ManagementStrategy; public class MicrometerRouteEventNotifier extends AbstractMicrometerEventNotifier<RouteEvent> { @@ -36,6 +37,8 @@ public class MicrometerRouteEventNotifier extends AbstractMicrometerEventNotifie private Gauge gaugeRunning; private Gauge gaugeReloaded; private MicrometerRouteEventNotifierNamingStrategy namingStrategy = MicrometerRouteEventNotifierNamingStrategy.DEFAULT; + boolean registerKamelets; + boolean registerTemplates = true; public MicrometerRouteEventNotifier() { super(RouteEvent.class); @@ -49,6 +52,15 @@ public class MicrometerRouteEventNotifier extends AbstractMicrometerEventNotifie this.namingStrategy = namingStrategy; } + @Override + protected void doInit() throws Exception { + ManagementStrategy ms = getCamelContext().getManagementStrategy(); + if (ms != null && ms.getManagementAgent() != null) { + registerKamelets = ms.getManagementAgent().getRegisterRoutesCreateByKamelet(); + registerTemplates = ms.getManagementAgent().getRegisterRoutesCreateByTemplate(); + } + } + @Override protected void doStart() throws Exception { super.doStart(); @@ -84,6 +96,14 @@ public class MicrometerRouteEventNotifier extends AbstractMicrometerEventNotifie @Override public void notify(CamelEvent eventObject) { + if (eventObject instanceof RouteEvent re) { + // skip routes that should not be included + boolean skip = (re.getRoute().isCreatedByKamelet() && !registerKamelets) + || (re.getRoute().isCreatedByRouteTemplate() && !registerTemplates); + if (skip) { + return; + } + } if (eventObject instanceof RouteAddedEvent) { routesAdded.incrementAndGet(); } else if (eventObject instanceof RouteRemovedEvent) { diff --git a/components/camel-micrometer/src/main/java/org/apache/camel/component/micrometer/routepolicy/MicrometerRoutePolicy.java b/components/camel-micrometer/src/main/java/org/apache/camel/component/micrometer/routepolicy/MicrometerRoutePolicy.java index 264cb58d6cf..74681d8797d 100644 --- a/components/camel-micrometer/src/main/java/org/apache/camel/component/micrometer/routepolicy/MicrometerRoutePolicy.java +++ b/components/camel-micrometer/src/main/java/org/apache/camel/component/micrometer/routepolicy/MicrometerRoutePolicy.java @@ -31,6 +31,7 @@ import org.apache.camel.NonManagedService; import org.apache.camel.Route; import org.apache.camel.RuntimeCamelException; import org.apache.camel.component.micrometer.MicrometerUtils; +import org.apache.camel.spi.ManagementStrategy; import org.apache.camel.support.ExchangeHelper; import org.apache.camel.support.RoutePolicySupport; import org.apache.camel.support.service.ServiceHelper; @@ -54,6 +55,8 @@ public class MicrometerRoutePolicy extends RoutePolicySupport implements NonMana private MicrometerRoutePolicyConfiguration configuration = MicrometerRoutePolicyConfiguration.DEFAULT; private final Map<Route, MetricsStatistics> statisticsMap = new HashMap<>(); + boolean registerKamelets; + boolean registerTemplates = true; private static final class MetricsStatistics { private final MeterRegistry meterRegistry; @@ -221,6 +224,12 @@ public class MicrometerRoutePolicy extends RoutePolicySupport implements NonMana public void onInit(Route route) { super.onInit(route); + ManagementStrategy ms = route.getCamelContext().getManagementStrategy(); + if (ms != null && ms.getManagementAgent() != null) { + registerKamelets = ms.getManagementAgent().getRegisterRoutesCreateByKamelet(); + registerTemplates = ms.getManagementAgent().getRegisterRoutesCreateByTemplate(); + } + if (getMeterRegistry() == null) { setMeterRegistry(MicrometerUtils.getOrCreateMeterRegistry( route.getCamelContext().getRegistry(), METRICS_REGISTRY_NAME)); @@ -248,7 +257,15 @@ public class MicrometerRoutePolicy extends RoutePolicySupport implements NonMana // for now we record only all the timings of a complete exchange (responses) // we have in-flight / total statistics already from camel-core statisticsMap.computeIfAbsent(route, - it -> new MetricsStatistics(getMeterRegistry(), it, getNamingStrategy(), configuration)); + it -> { + // skip routes that should not be included + boolean skip = (it.isCreatedByKamelet() && !registerKamelets) + || (it.isCreatedByRouteTemplate() && !registerTemplates); + if (skip) { + return null; + } + return new MetricsStatistics(getMeterRegistry(), it, getNamingStrategy(), configuration); + }); } @Override diff --git a/core/camel-api/src/main/java/org/apache/camel/Route.java b/core/camel-api/src/main/java/org/apache/camel/Route.java index a7d0f0cd054..d247d02240a 100644 --- a/core/camel-api/src/main/java/org/apache/camel/Route.java +++ b/core/camel-api/src/main/java/org/apache/camel/Route.java @@ -47,6 +47,7 @@ public interface Route extends RuntimeConfiguration { String NODE_PREFIX_ID_PROPERTY = "nodePrefixId"; String REST_PROPERTY = "rest"; String TEMPLATE_PROPERTY = "template"; + String KAMELET_PROPERTY = "kamelet"; String DESCRIPTION_PROPERTY = "description"; String CONFIGURATION_ID_PROPERTY = "configurationId"; String SUPERVISED = "supervised"; @@ -70,6 +71,21 @@ public interface Route extends RuntimeConfiguration { */ boolean isCustomId(); + /** + * Whether this route is a Rest DSL route. + */ + boolean isCreatedByRestDsl(); + + /** + * Whether this route was created from a route template (or a Kamelet). + */ + boolean isCreatedByRouteTemplate(); + + /** + * Whether this route was created from a Kamelet. + */ + boolean isCreatedByKamelet(); + /** * Gets the route group * diff --git a/core/camel-api/src/main/java/org/apache/camel/spi/ManagementAgent.java b/core/camel-api/src/main/java/org/apache/camel/spi/ManagementAgent.java index 4e1ee22dd01..214d5ddf4d6 100644 --- a/core/camel-api/src/main/java/org/apache/camel/spi/ManagementAgent.java +++ b/core/camel-api/src/main/java/org/apache/camel/spi/ManagementAgent.java @@ -199,6 +199,34 @@ public interface ManagementAgent extends Service { */ void setRegisterNewRoutes(Boolean registerNewRoutes); + /** + * Whether to register mbeans for routes created by a Kamelet + * <p/> + * This option is default <tt>false</tt>. + */ + Boolean getRegisterRoutesCreateByKamelet(); + + /** + * Whether to register mbeans for routes created by a Kamelet + * <p/> + * This option is default <tt>false</tt>. + */ + void setRegisterRoutesCreateByKamelet(Boolean registerRoutesCreateByKamelet); + + /** + * Whether to register mbeans for routes created by a route templates (not Kamelets) + * <p/> + * This option is default <tt>true</tt>. + */ + Boolean getRegisterRoutesCreateByTemplate(); + + /** + * Whether to register mbeans for routes created by a route templates (not Kamelets) + * <p/> + * This option is default <tt>true</tt>. + */ + void setRegisterRoutesCreateByTemplate(Boolean registerRoutesCreateByTemplate); + /** * Whether to remove detected sensitive information (such as passwords) from MBean names and attributes. * <p/> 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 b9d28cb530e..75b5de4cd2a 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 @@ -203,6 +203,21 @@ public interface UnitOfWork { */ int routeStackLevel(); + /** + * 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. + * <p> + * 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. + * + * @param includeRouteTemplate whether to include routes created by route templates + * @param includeKamelet whether to include routes created by kamelets + * @return the route level-of-depth + */ + int routeStackLevel(boolean includeRouteTemplate, boolean includeKamelet); + /** * 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/AbstractCamelContext.java b/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/AbstractCamelContext.java index 24cb8e2af08..d14bb4760cb 100644 --- a/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/AbstractCamelContext.java +++ b/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/AbstractCamelContext.java @@ -31,6 +31,7 @@ import java.util.List; import java.util.Map; import java.util.Optional; import java.util.Set; +import java.util.StringJoiner; import java.util.TreeSet; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.CopyOnWriteArrayList; @@ -2567,7 +2568,17 @@ public abstract class AbstractCamelContext extends BaseService && LOG.isInfoEnabled()) { int started = 0; int total = 0; + int kamelets = 0; + int templates = 0; + int rests = 0; int disabled = 0; + boolean registerKamelets = false; + boolean registerTemplates = true; + ManagementStrategy ms = getManagementStrategy(); + if (ms != null && ms.getManagementAgent() != null) { + registerKamelets = ms.getManagementAgent().getRegisterRoutesCreateByKamelet(); + registerTemplates = ms.getManagementAgent().getRegisterRoutesCreateByTemplate(); + } List<String> lines = new ArrayList<>(); List<String> configs = new ArrayList<>(); routeStartupOrder.sort(Comparator.comparingInt(RouteStartupOrder::getStartupOrder)); @@ -2575,9 +2586,20 @@ public abstract class AbstractCamelContext extends BaseService total++; String id = order.getRoute().getRouteId(); String status = getRouteStatus(id).name(); - if (ServiceStatus.Started.name().equals(status)) { + if (order.getRoute().isCreatedByKamelet()) { + kamelets++; + } else if (order.getRoute().isCreatedByRouteTemplate()) { + templates++; + } else if (order.getRoute().isCreatedByRestDsl()) { + rests++; + } + boolean skip = order.getRoute().isCreatedByRestDsl() + || (!registerKamelets && order.getRoute().isCreatedByKamelet()) + || (!registerTemplates && order.getRoute().isCreatedByRouteTemplate()); + if (!skip && ServiceStatus.Started.name().equals(status)) { started++; } + // use basic endpoint uri to not log verbose details or potential sensitive data String uri = order.getRoute().getEndpoint().getEndpointBaseUri(); uri = URISupport.sanitizeUri(uri); @@ -2585,7 +2607,9 @@ public abstract class AbstractCamelContext extends BaseService if (startupSummaryLevel == StartupSummaryLevel.Verbose && loc != null) { lines.add(String.format(" %s %s (%s) (source: %s)", status, id, uri, loc)); } else { - lines.add(String.format(" %s %s (%s)", status, id, uri)); + if (!skip) { + lines.add(String.format(" %s %s (%s)", status, id, uri)); + } } String cid = order.getRoute().getConfigurationId(); if (cid != null) { @@ -2601,6 +2625,15 @@ public abstract class AbstractCamelContext extends BaseService if (ServiceStatus.Stopped.name().equals(status)) { status = "Disabled"; } + if (route.isCreatedByKamelet()) { + kamelets++; + } else if (route.isCreatedByRouteTemplate()) { + templates++; + } else if (route.isCreatedByRestDsl()) { + rests++; + } + boolean skip = route.isCreatedByRestDsl() || (!registerKamelets && route.isCreatedByKamelet()) + || (!registerTemplates && route.isCreatedByRouteTemplate()); // use basic endpoint uri to not log verbose details or potential sensitive data String uri = route.getEndpoint().getEndpointBaseUri(); uri = URISupport.sanitizeUri(uri); @@ -2608,7 +2641,9 @@ public abstract class AbstractCamelContext extends BaseService if (startupSummaryLevel == StartupSummaryLevel.Verbose && loc != null) { lines.add(String.format(" %s %s (%s) (source: %s)", status, id, uri, loc)); } else { - lines.add(String.format(" %s %s (%s)", status, id, uri)); + if (!skip) { + lines.add(String.format(" %s %s (%s)", status, id, uri)); + } } String cid = route.getConfigurationId(); @@ -2617,19 +2652,38 @@ public abstract class AbstractCamelContext extends BaseService } } } + int newTotal = total; + if (!registerKamelets) { + newTotal -= kamelets; + } + if (!registerTemplates) { + newTotal -= templates; + } + newTotal -= rests; + StringJoiner sj = new StringJoiner(" "); + sj.add("total:" + newTotal); + if (total != started) { + sj.add("started:" + started); + } + if (kamelets > 0) { + sj.add("kamelets:" + kamelets); + } + if (templates > 0) { + sj.add("templates:" + templates); + } + if (rests > 0) { + sj.add("rest-dsl:" + rests); + } if (disabled > 0) { - LOG.info("Routes startup (total:{} started:{} disabled:{})", total, started, disabled); - } else if (total != started) { - LOG.info("Routes startup (total:{} started:{})", total, started); - } else { - LOG.info("Routes startup (started:{})", started); + sj.add("disabled:" + disabled); } + LOG.info(String.format("Routes startup (%s)", sj)); // if we are default/verbose then log each route line if (startupSummaryLevel == StartupSummaryLevel.Default || startupSummaryLevel == StartupSummaryLevel.Verbose) { for (String line : lines) { LOG.info(line); } - if (startupSummaryLevel == StartupSummaryLevel.Verbose) { + if (startupSummaryLevel == StartupSummaryLevel.Verbose && !configs.isEmpty()) { LOG.info("Routes configuration:"); for (String line : configs) { LOG.info(line); @@ -3024,6 +3078,16 @@ public abstract class AbstractCamelContext extends BaseService int total = 0; int stopped = 0; int forced = 0; + int kamelets = 0; + int templates = 0; + int rests = 0; + boolean registerKamelets = false; + boolean registerTemplates = true; + ManagementStrategy ms = getManagementStrategy(); + if (ms != null && ms.getManagementAgent() != null) { + registerKamelets = ms.getManagementAgent().getRegisterRoutesCreateByKamelet(); + registerTemplates = ms.getManagementAgent().getRegisterRoutesCreateByTemplate(); + } List<String> lines = new ArrayList<>(); final ShutdownStrategy shutdownStrategy = camelContextExtension.getShutdownStrategy(); @@ -3036,7 +3100,17 @@ public abstract class AbstractCamelContext extends BaseService total++; String id = order.getRoute().getRouteId(); String status = getRouteStatus(id).name(); - if (ServiceStatus.Stopped.name().equals(status)) { + if (order.getRoute().isCreatedByKamelet()) { + kamelets++; + } else if (order.getRoute().isCreatedByRouteTemplate()) { + templates++; + } else if (order.getRoute().isCreatedByRestDsl()) { + rests++; + } + boolean skip = order.getRoute().isCreatedByRestDsl() + || (!registerKamelets && order.getRoute().isCreatedByKamelet()) + || (!registerTemplates && order.getRoute().isCreatedByRouteTemplate()); + if (!skip && ServiceStatus.Stopped.name().equals(status)) { stopped++; } if (order.getRoute().getProperties().containsKey("forcedShutdown")) { @@ -3046,15 +3120,36 @@ public abstract class AbstractCamelContext extends BaseService // use basic endpoint uri to not log verbose details or potential sensitive data String uri = order.getRoute().getEndpoint().getEndpointBaseUri(); uri = URISupport.sanitizeUri(uri); - lines.add(String.format(" %s %s (%s)", status, id, uri)); + if (startupSummaryLevel == StartupSummaryLevel.Verbose || !skip) { + lines.add(String.format(" %s %s (%s)", status, id, uri)); + } + } + int newTotal = total; + if (!registerKamelets) { + newTotal -= kamelets; + } + if (!registerTemplates) { + newTotal -= templates; + } + newTotal -= rests; + StringJoiner sj = new StringJoiner(" "); + sj.add("total:" + newTotal); + if (total != stopped) { + sj.add("stopped:" + stopped); + } + if (kamelets > 0) { + sj.add("kamelets:" + kamelets); + } + if (templates > 0) { + sj.add("templates:" + templates); + } + if (rests > 0) { + sj.add("rest-dsl:" + rests); } if (forced > 0) { - logger.log(String.format("Routes stopped (total:%s stopped:%s forced:%s)", total, stopped, forced)); - } else if (total != stopped) { - logger.log(String.format("Routes stopped (total:%s stopped:%s)", total, stopped)); - } else { - logger.log(String.format("Routes stopped (stopped:%s)", stopped)); + sj.add("forced:" + forced); } + logger.log(String.format("Routes stopped (%s)", sj)); // if we are default/verbose then log each route line if (startupSummaryLevel == StartupSummaryLevel.Default || startupSummaryLevel == StartupSummaryLevel.Verbose) { for (String line : lines) { diff --git a/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/DefaultRoute.java b/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/DefaultRoute.java index 1e90f04be21..eab52da2dfd 100644 --- a/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/DefaultRoute.java +++ b/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/DefaultRoute.java @@ -141,6 +141,21 @@ public class DefaultRoute extends ServiceSupport implements Route { return "true".equals(properties.get(Route.CUSTOM_ID_PROPERTY)); } + @Override + public boolean isCreatedByRestDsl() { + return "true".equals(properties.get(Route.REST_PROPERTY)); + } + + @Override + public boolean isCreatedByRouteTemplate() { + return "true".equals(properties.get(Route.TEMPLATE_PROPERTY)); + } + + @Override + public boolean isCreatedByKamelet() { + return "true".equals(properties.get(Route.KAMELET_PROPERTY)); + } + @Override public String getGroup() { return (String) properties.get(Route.GROUP_PROPERTY); 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 c5230567ec3..51f8680b33f 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 @@ -367,6 +367,28 @@ public class DefaultUnitOfWork implements UnitOfWork { return routes.size(); } + public int routeStackLevel(boolean includeRouteTemplate, boolean includeKamelet) { + if (includeKamelet && includeRouteTemplate) { + return routes.size(); + } + + int level = 0; + for (Route r : routes) { + if (r.isCreatedByKamelet()) { + if (includeKamelet) { + level++; + } + } else if (r.isCreatedByRouteTemplate()) { + if (includeRouteTemplate) { + level++; + } + } else { + level++; + } + } + return level; + } + @Override public boolean isBeforeAfterProcess() { return false; 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 3341c80c43d..a75ea58d2fb 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 @@ -139,7 +139,7 @@ public class ConsumerDevConsole extends AbstractDevConsole { String id = route.getId(); ManagedRouteMBean mr = mcc.getManagedRoute(id); ManagedConsumerMBean mc = mcc.getManagedConsumer(id); - if (mc != null) { + if (mr != null && mc != null) { JsonObject jo = new JsonObject(); Integer inflight = mc.getInflightExchanges(); if (inflight == null) { 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 e060fb93607..1e6ee27a284 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 @@ -22,6 +22,7 @@ import java.util.Comparator; import java.util.Date; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.function.Function; import org.apache.camel.Exchange; @@ -359,6 +360,7 @@ public class RouteDevConsole extends AbstractDevConsole { routes.sort((o1, o2) -> o1.getRouteId().compareToIgnoreCase(o2.getRouteId())); routes.stream() .map(route -> mcc.getManagedRoute(route.getRouteId())) + .filter(Objects::nonNull) .filter(r -> accept(r, filter)) .filter(r -> accept(r, subPath)) .sorted(RouteDevConsole::sort) @@ -378,8 +380,7 @@ public class RouteDevConsole extends AbstractDevConsole { } private static int sort(ManagedRouteMBean o1, ManagedRouteMBean o2) { - // sort by id - return o1.getRouteId().compareTo(o2.getRouteId()); + return o1.getRouteId().compareToIgnoreCase(o2.getRouteId()); } private String getLoad1(ManagedRouteMBean mrb) { diff --git a/core/camel-console/src/main/java/org/apache/camel/impl/console/RouteDumpDevConsole.java b/core/camel-console/src/main/java/org/apache/camel/impl/console/RouteDumpDevConsole.java index 659f388c439..63c127b0d82 100644 --- a/core/camel-console/src/main/java/org/apache/camel/impl/console/RouteDumpDevConsole.java +++ b/core/camel-console/src/main/java/org/apache/camel/impl/console/RouteDumpDevConsole.java @@ -20,6 +20,7 @@ import java.io.StringReader; import java.util.ArrayList; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.function.Function; import org.apache.camel.Exchange; @@ -151,6 +152,7 @@ public class RouteDumpDevConsole extends AbstractDevConsole { routes.sort((o1, o2) -> o1.getRouteId().compareToIgnoreCase(o2.getRouteId())); routes.stream() .map(route -> mcc.getManagedRoute(route.getRouteId())) + .filter(Objects::nonNull) .filter(r -> accept(r, filter)) .filter(r -> accept(r, subPath)) .sorted(RouteDumpDevConsole::sort) diff --git a/core/camel-console/src/main/java/org/apache/camel/impl/console/SourceDevConsole.java b/core/camel-console/src/main/java/org/apache/camel/impl/console/SourceDevConsole.java index ea96a307af6..c848030b181 100644 --- a/core/camel-console/src/main/java/org/apache/camel/impl/console/SourceDevConsole.java +++ b/core/camel-console/src/main/java/org/apache/camel/impl/console/SourceDevConsole.java @@ -20,6 +20,7 @@ import java.io.LineNumberReader; import java.util.ArrayList; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.function.Function; import org.apache.camel.Exchange; @@ -138,6 +139,7 @@ public class SourceDevConsole extends AbstractDevConsole { routes.sort((o1, o2) -> o1.getRouteId().compareToIgnoreCase(o2.getRouteId())); routes.stream() .map(route -> mcc.getManagedRoute(route.getRouteId())) + .filter(Objects::nonNull) .filter(r -> accept(r, filter)) .filter(r -> accept(r, subPath)) .sorted(SourceDevConsole::sort) diff --git a/core/camel-console/src/main/java/org/apache/camel/impl/console/TopDevConsole.java b/core/camel-console/src/main/java/org/apache/camel/impl/console/TopDevConsole.java index 995c25a952a..54358b71059 100644 --- a/core/camel-console/src/main/java/org/apache/camel/impl/console/TopDevConsole.java +++ b/core/camel-console/src/main/java/org/apache/camel/impl/console/TopDevConsole.java @@ -21,6 +21,7 @@ import java.util.ArrayList; import java.util.Collection; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.function.Function; import org.apache.camel.Exchange; @@ -270,6 +271,7 @@ public class TopDevConsole extends AbstractDevConsole { List<Route> routes = getCamelContext().getRoutes(); routes.stream() .map(route -> mcc.getManagedRoute(route.getRouteId())) + .filter(Objects::nonNull) .filter(r -> acceptRoute(r, filter)) .sorted(TopDevConsole::top) .limit(max) @@ -284,6 +286,7 @@ public class TopDevConsole extends AbstractDevConsole { routes.stream() .map(route -> mcc.getManagedRoute(route.getRouteId())) + .filter(Objects::nonNull) .filter(r -> acceptRoute(r, subPath)) .forEach(r -> { try { diff --git a/core/camel-core-model/src/main/java/org/apache/camel/model/RouteDefinition.java b/core/camel-core-model/src/main/java/org/apache/camel/model/RouteDefinition.java index 7b274a5ef1c..aa78b73fdc4 100644 --- a/core/camel-core-model/src/main/java/org/apache/camel/model/RouteDefinition.java +++ b/core/camel-core-model/src/main/java/org/apache/camel/model/RouteDefinition.java @@ -86,6 +86,7 @@ public class RouteDefinition extends OutputDefinition<RouteDefinition> private boolean contextScopedErrorHandler = true; private Boolean rest; private Boolean template; + private Boolean kamelet; private RestDefinition restDefinition; private RestBindingDefinition restBindingDefinition; private InputTypeDefinition inputType; @@ -1178,7 +1179,7 @@ public class RouteDefinition extends OutputDefinition<RouteDefinition> } /** - * This route is created from a route template. + * This route is created from a route template (or from a Kamelet). */ public void setTemplate(Boolean template) { this.template = template; @@ -1190,6 +1191,19 @@ public class RouteDefinition extends OutputDefinition<RouteDefinition> return template; } + /** + * This route is created from a Kamelet. + */ + public void setKamelet(Boolean kamelet) { + this.kamelet = kamelet; + } + + @XmlAttribute + @Metadata(label = "advanced") + public Boolean isKamelet() { + return kamelet; + } + public RestDefinition getRestDefinition() { return restDefinition; } diff --git a/core/camel-core-processor/src/main/java/org/apache/camel/processor/SendProcessor.java b/core/camel-core-processor/src/main/java/org/apache/camel/processor/SendProcessor.java index b04e75a88fb..04840285980 100644 --- a/core/camel-core-processor/src/main/java/org/apache/camel/processor/SendProcessor.java +++ b/core/camel-core-processor/src/main/java/org/apache/camel/processor/SendProcessor.java @@ -313,6 +313,9 @@ public class SendProcessor extends AsyncProcessorSupport implements Traceable, E // yes we can optimize and use the producer directly for sending if (destination.isSingletonProducer()) { this.producer = destination.createAsyncProducer(); + if (this.producer instanceof RouteIdAware ria) { + ria.setRouteId(getRouteId()); + } // ensure the producer is managed and started camelContext.addService(this.producer, true, true); } else { diff --git a/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/RouteReifier.java b/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/RouteReifier.java index 31a92c2582e..a41d8cbf34c 100644 --- a/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/RouteReifier.java +++ b/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/RouteReifier.java @@ -395,6 +395,8 @@ public class RouteReifier extends ProcessorReifier<RouteDefinition> { routeProperties.put(Route.REST_PROPERTY, rest); String template = Boolean.toString(definition.isTemplate() != null && definition.isTemplate()); routeProperties.put(Route.TEMPLATE_PROPERTY, template); + String kamelet = Boolean.toString(definition.isKamelet() != null && definition.isKamelet()); + routeProperties.put(Route.KAMELET_PROPERTY, kamelet); if (definition.getAppliedRouteConfigurationIds() != null) { routeProperties.put(Route.CONFIGURATION_ID_PROPERTY, String.join(",", definition.getAppliedRouteConfigurationIds())); diff --git a/core/camel-main/src/generated/java/org/apache/camel/main/MainConfigurationPropertiesConfigurer.java b/core/camel-main/src/generated/java/org/apache/camel/main/MainConfigurationPropertiesConfigurer.java index ca08ad52360..7d2f91e74db 100644 --- a/core/camel-main/src/generated/java/org/apache/camel/main/MainConfigurationPropertiesConfigurer.java +++ b/core/camel-main/src/generated/java/org/apache/camel/main/MainConfigurationPropertiesConfigurer.java @@ -125,6 +125,10 @@ public class MainConfigurationPropertiesConfigurer extends org.apache.camel.supp case "JmxManagementMBeansLevel": target.setJmxManagementMBeansLevel(property(camelContext, org.apache.camel.ManagementMBeansLevel.class, value)); return true; case "jmxmanagementnamepattern": case "JmxManagementNamePattern": target.setJmxManagementNamePattern(property(camelContext, java.lang.String.class, value)); return true; + case "jmxmanagementregisterroutescreatebykamelet": + case "JmxManagementRegisterRoutesCreateByKamelet": target.setJmxManagementRegisterRoutesCreateByKamelet(property(camelContext, boolean.class, value)); return true; + case "jmxmanagementregisterroutescreatebytemplate": + case "JmxManagementRegisterRoutesCreateByTemplate": target.setJmxManagementRegisterRoutesCreateByTemplate(property(camelContext, boolean.class, value)); return true; case "jmxmanagementstatisticslevel": case "JmxManagementStatisticsLevel": target.setJmxManagementStatisticsLevel(property(camelContext, org.apache.camel.ManagementStatisticsLevel.class, value)); return true; case "jmxupdaterouteenabled": @@ -366,6 +370,10 @@ public class MainConfigurationPropertiesConfigurer extends org.apache.camel.supp case "JmxManagementMBeansLevel": return org.apache.camel.ManagementMBeansLevel.class; case "jmxmanagementnamepattern": case "JmxManagementNamePattern": return java.lang.String.class; + case "jmxmanagementregisterroutescreatebykamelet": + case "JmxManagementRegisterRoutesCreateByKamelet": return boolean.class; + case "jmxmanagementregisterroutescreatebytemplate": + case "JmxManagementRegisterRoutesCreateByTemplate": return boolean.class; case "jmxmanagementstatisticslevel": case "JmxManagementStatisticsLevel": return org.apache.camel.ManagementStatisticsLevel.class; case "jmxupdaterouteenabled": @@ -608,6 +616,10 @@ public class MainConfigurationPropertiesConfigurer extends org.apache.camel.supp case "JmxManagementMBeansLevel": return target.getJmxManagementMBeansLevel(); case "jmxmanagementnamepattern": case "JmxManagementNamePattern": return target.getJmxManagementNamePattern(); + case "jmxmanagementregisterroutescreatebykamelet": + case "JmxManagementRegisterRoutesCreateByKamelet": return target.isJmxManagementRegisterRoutesCreateByKamelet(); + case "jmxmanagementregisterroutescreatebytemplate": + case "JmxManagementRegisterRoutesCreateByTemplate": return target.isJmxManagementRegisterRoutesCreateByTemplate(); case "jmxmanagementstatisticslevel": case "JmxManagementStatisticsLevel": return target.getJmxManagementStatisticsLevel(); case "jmxupdaterouteenabled": diff --git a/core/camel-main/src/generated/resources/META-INF/camel-main-configuration-metadata.json b/core/camel-main/src/generated/resources/META-INF/camel-main-configuration-metadata.json index 127e310a2c6..f1e51f670bf 100644 --- a/core/camel-main/src/generated/resources/META-INF/camel-main-configuration-metadata.json +++ b/core/camel-main/src/generated/resources/META-INF/camel-main-configuration-metadata.json @@ -70,6 +70,8 @@ { "name": "camel.main.jmxEnabled", "description": "Enable JMX in your Camel application.", "sourceType": "org.apache.camel.main.DefaultConfigurationProperties", "type": "boolean", "javaType": "boolean", "defaultValue": true }, { "name": "camel.main.jmxManagementMBeansLevel", "description": "Sets the mbeans registration level. The default value is Default.", "sourceType": "org.apache.camel.main.DefaultConfigurationProperties", "type": "object", "javaType": "org.apache.camel.ManagementMBeansLevel", "defaultValue": "Default" }, { "name": "camel.main.jmxManagementNamePattern", "description": "The naming pattern for creating the CamelContext JMX management name. The default pattern is #name#", "sourceType": "org.apache.camel.main.DefaultConfigurationProperties", "type": "string", "javaType": "java.lang.String", "defaultValue": "#name#" }, + { "name": "camel.main.jmxManagementRegisterRoutesCreateByKamelet", "description": "Whether routes created by Kamelets should be registered for JMX management. Enabling this allows to have fine-grained monitoring and management of every route created via Kamelets. This is default disabled as a Kamelet is intended as a component (black-box) and its implementation details as Camel route makes the overall management and monitoring of Camel applications more verbose. During development of [...] + { "name": "camel.main.jmxManagementRegisterRoutesCreateByTemplate", "description": "Whether routes created by route templates (not Kamelets) should be registered for JMX management. Enabling this allows to have fine-grained monitoring and management of every route created via route templates. This is default enabled (unlike Kamelets) as routes created via templates is regarded as standard routes, and should be available for management and monitoring.", "sourceType": "org.apache.camel [...] { "name": "camel.main.jmxManagementStatisticsLevel", "description": "Sets the JMX statistics level, the level can be set to Extended to gather additional information The default value is Default.", "sourceType": "org.apache.camel.main.DefaultConfigurationProperties", "type": "object", "javaType": "org.apache.camel.ManagementStatisticsLevel", "defaultValue": "Default", "enum": [ "Extended", "Default", "RoutesOnly", "Off" ] }, { "name": "camel.main.jmxUpdateRouteEnabled", "description": "Whether to allow updating routes at runtime via JMX using the ManagedRouteMBean. This is disabled by default, but can be enabled for development and troubleshooting purposes, such as updating routes in an existing running Camel via JMX and other tools.", "sourceType": "org.apache.camel.main.DefaultConfigurationProperties", "type": "boolean", "javaType": "boolean", "defaultValue": "false" }, { "name": "camel.main.lightweight", "description": "Configure the context to be lightweight. This will trigger some optimizations and memory reduction options. Lightweight context have some limitations. At this moment, dynamic endpoint destinations are not supported.", "sourceType": "org.apache.camel.main.DefaultConfigurationProperties", "type": "boolean", "javaType": "boolean", "defaultValue": "false" }, diff --git a/core/camel-main/src/main/docs/main.adoc b/core/camel-main/src/main/docs/main.adoc index c709db4e390..a12a25f0edb 100644 --- a/core/camel-main/src/main/docs/main.adoc +++ b/core/camel-main/src/main/docs/main.adoc @@ -19,7 +19,7 @@ The following tables lists all the options: // main options: START === Camel Main configurations -The camel.main supports 117 options, which are listed below. +The camel.main supports 119 options, which are listed below. [width="100%",cols="2,5,^1,2",options="header"] |=== @@ -76,6 +76,8 @@ The camel.main supports 117 options, which are listed below. | *camel.main.jmxEnabled* | Enable JMX in your Camel application. | true | boolean | *camel.main.jmxManagementMBeans{zwsp}Level* | Sets the mbeans registration level. The default value is Default. | Default | ManagementMBeansLevel | *camel.main.jmxManagementName{zwsp}Pattern* | The naming pattern for creating the CamelContext JMX management name. The default pattern is #name# | #name# | String +| *camel.main.jmxManagement{zwsp}RegisterRoutesCreateByKamelet* | Whether routes created by Kamelets should be registered for JMX management. Enabling this allows to have fine-grained monitoring and management of every route created via Kamelets. This is default disabled as a Kamelet is intended as a component (black-box) and its implementation details as Camel route makes the overall management and monitoring of Camel applications more verbose. During development of Kamelets then enabli [...] +| *camel.main.jmxManagement{zwsp}RegisterRoutesCreateByTemplate* | Whether routes created by route templates (not Kamelets) should be registered for JMX management. Enabling this allows to have fine-grained monitoring and management of every route created via route templates. This is default enabled (unlike Kamelets) as routes created via templates is regarded as standard routes, and should be available for management and monitoring. | true | boolean | *camel.main.jmxManagement{zwsp}StatisticsLevel* | Sets the JMX statistics level, the level can be set to Extended to gather additional information The default value is Default. | Default | ManagementStatisticsLevel | *camel.main.jmxUpdateRoute{zwsp}Enabled* | Whether to allow updating routes at runtime via JMX using the ManagedRouteMBean. This is disabled by default, but can be enabled for development and troubleshooting purposes, such as updating routes in an existing running Camel via JMX and other tools. | false | boolean | *camel.main.lightweight* | Configure the context to be lightweight. This will trigger some optimizations and memory reduction options. Lightweight context have some limitations. At this moment, dynamic endpoint destinations are not supported. | false | boolean diff --git a/core/camel-main/src/main/java/org/apache/camel/main/DefaultConfigurationConfigurer.java b/core/camel-main/src/main/java/org/apache/camel/main/DefaultConfigurationConfigurer.java index 4d4f664c20f..22674dad7f2 100644 --- a/core/camel-main/src/main/java/org/apache/camel/main/DefaultConfigurationConfigurer.java +++ b/core/camel-main/src/main/java/org/apache/camel/main/DefaultConfigurationConfigurer.java @@ -294,6 +294,10 @@ public final class DefaultConfigurationConfigurer { .setManagementNamePattern(config.getJmxManagementNamePattern()); camelContext.getManagementStrategy().getManagementAgent() .setUpdateRouteEnabled(config.isJmxUpdateRouteEnabled()); + camelContext.getManagementStrategy().getManagementAgent() + .setRegisterRoutesCreateByKamelet(config.isJmxManagementRegisterRoutesCreateByKamelet()); + camelContext.getManagementStrategy().getManagementAgent() + .setRegisterRoutesCreateByTemplate(config.isJmxManagementRegisterRoutesCreateByTemplate()); } if (config.isCamelEventsTimestampEnabled()) { camelContext.getManagementStrategy().getEventFactory().setTimestampEnabled(true); diff --git a/core/camel-main/src/main/java/org/apache/camel/main/DefaultConfigurationProperties.java b/core/camel-main/src/main/java/org/apache/camel/main/DefaultConfigurationProperties.java index 2e3fc64a8f3..921db5e0faa 100644 --- a/core/camel-main/src/main/java/org/apache/camel/main/DefaultConfigurationProperties.java +++ b/core/camel-main/src/main/java/org/apache/camel/main/DefaultConfigurationProperties.java @@ -101,6 +101,8 @@ public abstract class DefaultConfigurationProperties<T> { @Metadata(defaultValue = "Default") private ManagementStatisticsLevel jmxManagementStatisticsLevel = ManagementStatisticsLevel.Default; private String jmxManagementNamePattern = "#name#"; + private boolean jmxManagementRegisterRoutesCreateByKamelet; + private boolean jmxManagementRegisterRoutesCreateByTemplate = true; private boolean camelEventsTimestampEnabled; private boolean useMdcLogging; private String mdcLoggingKeysPattern; @@ -997,6 +999,41 @@ public abstract class DefaultConfigurationProperties<T> { this.jmxManagementNamePattern = jmxManagementNamePattern; } + public boolean isJmxManagementRegisterRoutesCreateByKamelet() { + return jmxManagementRegisterRoutesCreateByKamelet; + } + + /** + * Whether routes created by Kamelets should be registered for JMX management. Enabling this allows to have + * fine-grained monitoring and management of every route created via Kamelets. + * + * This is default disabled as a Kamelet is intended as a component (black-box) and its implementation details as + * Camel route makes the overall management and monitoring of Camel applications more verbose. + * + * During development of Kamelets then enabling this will make it possible for developers to do fine-grained + * performance inspection and identify potential bottlenecks in the Kamelet routes. + * + * However, for production usage then keeping this disabled is recommended. + */ + public void setJmxManagementRegisterRoutesCreateByKamelet(boolean jmxManagementRegisterRoutesCreateByKamelet) { + this.jmxManagementRegisterRoutesCreateByKamelet = jmxManagementRegisterRoutesCreateByKamelet; + } + + public boolean isJmxManagementRegisterRoutesCreateByTemplate() { + return jmxManagementRegisterRoutesCreateByTemplate; + } + + /** + * Whether routes created by route templates (not Kamelets) should be registered for JMX management. Enabling this + * allows to have fine-grained monitoring and management of every route created via route templates. + * + * This is default enabled (unlike Kamelets) as routes created via templates is regarded as standard routes, and + * should be available for management and monitoring. + */ + public void setJmxManagementRegisterRoutesCreateByTemplate(boolean jmxManagementRegisterRoutesCreateByTemplate) { + this.jmxManagementRegisterRoutesCreateByTemplate = jmxManagementRegisterRoutesCreateByTemplate; + } + public boolean isCamelEventsTimestampEnabled() { return camelEventsTimestampEnabled; } @@ -2201,6 +2238,35 @@ public abstract class DefaultConfigurationProperties<T> { return (T) this; } + /** + * Whether routes created by Kamelets should be registered for JMX management. Enabling this allows to have + * fine-grained monitoring and management of every route created via Kamelets. + * + * This is default disabled as a Kamelet is intended as a component (black-box) and its implementation details as + * Camel route makes the overall management and monitoring of Camel applications more verbose. + * + * During development of Kamelets then enabling this will make it possible for developers to do fine-grained + * performance inspection and identify potential bottlenecks in the Kamelet routes. + * + * However, for production usage then keeping this disabled is recommended. + */ + public T withJmxManagementRegisterRoutesCreateByKamelet(boolean jmxManagementRegisterRoutesCreateByKamelet) { + this.jmxManagementRegisterRoutesCreateByKamelet = jmxManagementRegisterRoutesCreateByKamelet; + return (T) this; + } + + /** + * Whether routes created by route templates (not Kamelets) should be registered for JMX management. Enabling this + * allows to have fine-grained monitoring and management of every route created via route templates. + * + * This is default enabled (unlike Kamelets) as routes created via templates is regarded as standard routes, and + * should be available for management and monitoring. + */ + public T withJmxManagementRegisterRoutesCreateByTemplate(boolean jmxManagementRegisterRoutesCreateByTemplate) { + this.jmxManagementRegisterRoutesCreateByTemplate = jmxManagementRegisterRoutesCreateByTemplate; + return (T) this; + } + /** * Whether to include timestamps for all emitted Camel Events. Enabling this allows to know fine-grained at what * time each event was emitted, which can be used for reporting to report exactly the time of the events. This is by diff --git a/core/camel-management-api/src/main/java/org/apache/camel/api/management/JmxSystemPropertyKeys.java b/core/camel-management-api/src/main/java/org/apache/camel/api/management/JmxSystemPropertyKeys.java index 51eafd2897f..dfe24f32a79 100644 --- a/core/camel-management-api/src/main/java/org/apache/camel/api/management/JmxSystemPropertyKeys.java +++ b/core/camel-management-api/src/main/java/org/apache/camel/api/management/JmxSystemPropertyKeys.java @@ -52,6 +52,12 @@ public final class JmxSystemPropertyKeys { // whether to register when starting new routes public static final String REGISTER_NEW_ROUTES = "org.apache.camel.jmx.registerNewRoutes"; + // whether to register routes created by route templates (not kamelets) + public static final String REGISTER_ROUTES_CREATED_BY_TEMPLATE = "org.apache.camel.jmx.registerRoutesCreateByTemplate"; + + // whether to register routes created by Kamelets + public static final String REGISTER_ROUTES_CREATED_BY_KAMELET = "org.apache.camel.jmx.registerRoutesCreateByKamelet"; + // Whether to remove detected sensitive information (such as passwords) from MBean names and attributes. public static final String MASK = "org.apache.camel.jmx.mask"; diff --git a/core/camel-management-api/src/main/java/org/apache/camel/api/management/mbean/ManagedRouteMBean.java b/core/camel-management-api/src/main/java/org/apache/camel/api/management/mbean/ManagedRouteMBean.java index a431ce16d6a..e22e393b6a5 100644 --- a/core/camel-management-api/src/main/java/org/apache/camel/api/management/mbean/ManagedRouteMBean.java +++ b/core/camel-management-api/src/main/java/org/apache/camel/api/management/mbean/ManagedRouteMBean.java @@ -34,6 +34,12 @@ public interface ManagedRouteMBean extends ManagedPerformanceCounterMBean { @ManagedAttribute(description = "Route Group") String getRouteGroup(); + @ManagedAttribute(description = "Is this route created from a route template (or Kamelet)") + boolean isCreatedByRouteTemplate(); + + @ManagedAttribute(description = "Is this route created from a Kamelet") + boolean isCreatedByKamelet(); + @ManagedAttribute(description = "Route Properties") TabularData getRouteProperties(); diff --git a/core/camel-management/src/main/java/org/apache/camel/management/DefaultManagementAgent.java b/core/camel-management/src/main/java/org/apache/camel/management/DefaultManagementAgent.java index ae761567c8a..fb6c3ef83e0 100644 --- a/core/camel-management/src/main/java/org/apache/camel/management/DefaultManagementAgent.java +++ b/core/camel-management/src/main/java/org/apache/camel/management/DefaultManagementAgent.java @@ -69,6 +69,8 @@ public class DefaultManagementAgent extends ServiceSupport implements Management private Boolean endpointRuntimeStatisticsEnabled; private Boolean registerAlways = false; private Boolean registerNewRoutes = true; + private Boolean registerRoutesCreateByKamelet = false; + private Boolean registerRoutesCreateByTemplate = true; private Boolean mask = true; private Boolean includeHostName = false; private Boolean useHostIPAddress = false; @@ -113,6 +115,14 @@ public class DefaultManagementAgent extends ServiceSupport implements Management registerNewRoutes = Boolean.getBoolean(JmxSystemPropertyKeys.REGISTER_NEW_ROUTES); values.put(JmxSystemPropertyKeys.REGISTER_NEW_ROUTES, registerNewRoutes); } + if (System.getProperty(JmxSystemPropertyKeys.REGISTER_ROUTES_CREATED_BY_TEMPLATE) != null) { + registerRoutesCreateByTemplate = Boolean.getBoolean(JmxSystemPropertyKeys.REGISTER_ROUTES_CREATED_BY_TEMPLATE); + values.put(JmxSystemPropertyKeys.REGISTER_ROUTES_CREATED_BY_TEMPLATE, registerRoutesCreateByTemplate); + } + if (System.getProperty(JmxSystemPropertyKeys.REGISTER_ROUTES_CREATED_BY_KAMELET) != null) { + registerRoutesCreateByKamelet = Boolean.getBoolean(JmxSystemPropertyKeys.REGISTER_ROUTES_CREATED_BY_KAMELET); + values.put(JmxSystemPropertyKeys.REGISTER_ROUTES_CREATED_BY_KAMELET, registerRoutesCreateByKamelet); + } if (System.getProperty(JmxSystemPropertyKeys.MASK) != null) { mask = Boolean.getBoolean(JmxSystemPropertyKeys.MASK); values.put(JmxSystemPropertyKeys.MASK, mask); @@ -222,6 +232,22 @@ public class DefaultManagementAgent extends ServiceSupport implements Management this.registerNewRoutes = registerNewRoutes; } + public Boolean getRegisterRoutesCreateByKamelet() { + return registerRoutesCreateByKamelet != null && registerRoutesCreateByKamelet; + } + + public void setRegisterRoutesCreateByKamelet(Boolean registerRoutesCreateByKamelet) { + this.registerRoutesCreateByKamelet = registerRoutesCreateByKamelet; + } + + public Boolean getRegisterRoutesCreateByTemplate() { + return registerRoutesCreateByTemplate != null && registerRoutesCreateByTemplate; + } + + public void setRegisterRoutesCreateByTemplate(Boolean registerRoutesCreateByTemplate) { + this.registerRoutesCreateByTemplate = registerRoutesCreateByTemplate; + } + @Override public Boolean getMask() { return mask != null && mask; diff --git a/core/camel-management/src/main/java/org/apache/camel/management/JmxManagementLifecycleStrategy.java b/core/camel-management/src/main/java/org/apache/camel/management/JmxManagementLifecycleStrategy.java index 426ce12f53b..16d230ce87a 100644 --- a/core/camel-management/src/main/java/org/apache/camel/management/JmxManagementLifecycleStrategy.java +++ b/core/camel-management/src/main/java/org/apache/camel/management/JmxManagementLifecycleStrategy.java @@ -931,6 +931,15 @@ public class JmxManagementLifecycleStrategy extends ServiceSupport implements Li return false; } + if (route != null && route.isCreatedByKamelet() && !agent.getRegisterRoutesCreateByKamelet()) { + // skip routes created from kamelets + return false; + } + if (route != null && route.isCreatedByRouteTemplate() && !agent.getRegisterRoutesCreateByTemplate()) { + // skip routes created from route templates + return false; + } + // always register if we are starting CamelContext if (getCamelContext().getStatus().isStarting() || getCamelContext().getStatus().isInitializing()) { 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 7f1fecc0631..000b07c00de 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 @@ -61,10 +61,14 @@ public class ManagedCamelContext extends ManagedPerformanceCounter implements Ti private final LoadTriplet load = new LoadTriplet(); private final LoadThroughput thp = new LoadThroughput(); private final String jmxDomain; + private final boolean includeRouteTemplates; + private final boolean includeKamelets; public ManagedCamelContext(CamelContext context) { this.context = context; this.jmxDomain = context.getManagementStrategy().getManagementAgent().getMBeanObjectDomainName(); + this.includeRouteTemplates = context.getManagementStrategy().getManagementAgent().getRegisterRoutesCreateByTemplate(); + this.includeKamelets = context.getManagementStrategy().getManagementAgent().getRegisterRoutesCreateByKamelet(); } @Override @@ -83,7 +87,7 @@ public class ManagedCamelContext extends ManagedPerformanceCounter implements Ti // we should only count this as 1 instead of 3. UnitOfWork uow = exchange.getUnitOfWork(); if (uow != null) { - int level = uow.routeStackLevel(); + int level = uow.routeStackLevel(includeRouteTemplates, includeKamelets); if (level <= 1) { super.completedExchange(exchange, time); } @@ -100,7 +104,7 @@ public class ManagedCamelContext extends ManagedPerformanceCounter implements Ti // we should only count this as 1 instead of 3. UnitOfWork uow = exchange.getUnitOfWork(); if (uow != null) { - int level = uow.routeStackLevel(); + int level = uow.routeStackLevel(includeRouteTemplates, includeKamelets); if (level <= 1) { super.failedExchange(exchange); } @@ -117,7 +121,7 @@ public class ManagedCamelContext extends ManagedPerformanceCounter implements Ti // we should only count this as 1 instead of 3. UnitOfWork uow = exchange.getUnitOfWork(); if (uow != null) { - int level = uow.routeStackLevel(); + int level = uow.routeStackLevel(includeRouteTemplates, includeKamelets); if (level <= 1) { super.processExchange(exchange, type); } @@ -790,15 +794,4 @@ public class ManagedCamelContext extends ManagedPerformanceCounter implements Ti } } - /** - * Used for sorting the routes mbeans accordingly to their ids. - */ - private static final class RouteMBeans implements Comparator<ManagedRouteMBean> { - - @Override - public int compare(ManagedRouteMBean o1, ManagedRouteMBean o2) { - return o1.getRouteId().compareToIgnoreCase(o2.getRouteId()); - } - } - } diff --git a/core/camel-management/src/main/java/org/apache/camel/management/mbean/ManagedRoute.java b/core/camel-management/src/main/java/org/apache/camel/management/mbean/ManagedRoute.java index 3cb8b1581f4..3d46f5f824f 100644 --- a/core/camel-management/src/main/java/org/apache/camel/management/mbean/ManagedRoute.java +++ b/core/camel-management/src/main/java/org/apache/camel/management/mbean/ManagedRoute.java @@ -129,6 +129,16 @@ public class ManagedRoute extends ManagedPerformanceCounter implements TimerList return route.getGroup(); } + @Override + public boolean isCreatedByRouteTemplate() { + return "true".equals(route.getProperties().getOrDefault(Route.TEMPLATE_PROPERTY, "false")); + } + + @Override + public boolean isCreatedByKamelet() { + return "true".equals(route.getProperties().getOrDefault(Route.KAMELET_PROPERTY, "false")); + } + @Override public TabularData getRouteProperties() { try { diff --git a/core/camel-xml-io/src/generated/java/org/apache/camel/xml/in/ModelParser.java b/core/camel-xml-io/src/generated/java/org/apache/camel/xml/in/ModelParser.java index 1e3b60f0e2d..a1823324f52 100644 --- a/core/camel-xml-io/src/generated/java/org/apache/camel/xml/in/ModelParser.java +++ b/core/camel-xml-io/src/generated/java/org/apache/camel/xml/in/ModelParser.java @@ -1077,6 +1077,7 @@ public class ModelParser extends BaseParser { case "from": def.setInput(doParseFromDefinition()); break; case "inputType": def.setInputType(doParseInputTypeDefinition()); break; case "outputType": def.setOutputType(doParseOutputTypeDefinition()); break; + case "kamelet": def.setKamelet(Boolean.valueOf(doParseText())); break; case "rest": def.setRest(Boolean.valueOf(doParseText())); break; case "routeProperty": doAdd(doParsePropertyDefinition(), def.getRouteProperties(), def::setRouteProperties); break; case "template": def.setTemplate(Boolean.valueOf(doParseText())); break; diff --git a/core/camel-xml-io/src/generated/java/org/apache/camel/xml/out/ModelWriter.java b/core/camel-xml-io/src/generated/java/org/apache/camel/xml/out/ModelWriter.java index b476ea80af6..4101ef5bc7b 100644 --- a/core/camel-xml-io/src/generated/java/org/apache/camel/xml/out/ModelWriter.java +++ b/core/camel-xml-io/src/generated/java/org/apache/camel/xml/out/ModelWriter.java @@ -2098,6 +2098,7 @@ public class ModelWriter extends BaseWriter { doWriteAttribute("logMask", def.getLogMask()); doWriteAttribute("nodePrefixId", def.getNodePrefixId()); doWriteAttribute("messageHistory", def.getMessageHistory()); + doWriteAttribute("kamelet", toString(def.isKamelet())); doWriteAttribute("autoStartup", def.getAutoStartup()); doWriteAttribute("delayer", def.getDelayer()); doWriteAttribute("group", def.getGroup()); diff --git a/core/camel-yaml-io/src/generated/java/org/apache/camel/yaml/out/ModelWriter.java b/core/camel-yaml-io/src/generated/java/org/apache/camel/yaml/out/ModelWriter.java index d0e72f25c78..16468140df5 100644 --- a/core/camel-yaml-io/src/generated/java/org/apache/camel/yaml/out/ModelWriter.java +++ b/core/camel-yaml-io/src/generated/java/org/apache/camel/yaml/out/ModelWriter.java @@ -2098,6 +2098,7 @@ public class ModelWriter extends BaseWriter { doWriteAttribute("logMask", def.getLogMask()); doWriteAttribute("nodePrefixId", def.getNodePrefixId()); doWriteAttribute("messageHistory", def.getMessageHistory()); + doWriteAttribute("kamelet", toString(def.isKamelet())); doWriteAttribute("autoStartup", def.getAutoStartup()); doWriteAttribute("delayer", def.getDelayer()); doWriteAttribute("group", def.getGroup()); diff --git a/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_5.adoc b/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_5.adoc index d63ab7d76bd..379f81d2370 100644 --- a/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_5.adoc +++ b/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_5.adoc @@ -8,6 +8,10 @@ from both 4.0 to 4.1 and 4.1 to 4.2. === camel-core +Camel startup summary will now report total number of routes without (internal routes created by Kamelets or Rest DSL). +This ensures the total number better reflect the total number of user created routes. The summary now includes a separate +number of Kamelets and Rest DSL routes. See also the camel-kamelet section. + === Intercept EIP The `interceptFrom` and `interceptSentToEndpoint` EIPs is now storing the intercepted endpoint using key `Exchange.INTERCEPTED_ENDPOINT` @@ -26,3 +30,20 @@ After: ---- String uri = exchange.getProperty(Exchange.INTERCEPTED_ENDPOINT, String.class); ---- + +=== camel-kamelet + +Routes created by Kamelets are no longer registered as JMX MBeans to avoid cluttering up with unwanted MBeans, as a Kamelet +is intended to act like a Camel component, despite its implementation is Camel routes. This means that the number of routes +listed from JMX will no longer include Kamelet routes. + +The old behaviour can be enabled by setting `registerRoutesCreateByKamelet=true` +on the `ManagementAgent` object. See more in the xref:jmx.adoc[JMX] documentation. + +=== camel-micrometer and camel-metrics + +Due to Kamelets are changed to act more like a Camel component, and not expose internal details as JMX MBeans, then +micrometer and metrics no longer include statistics for those Kamelet routes. + +The old behaviour can be enabled by setting `registerRoutesCreateByKamelet=true` +on the `ManagementAgent` object. See more in the xref:jmx.adoc[JMX] documentation. diff --git a/docs/user-manual/modules/ROOT/pages/jmx.adoc b/docs/user-manual/modules/ROOT/pages/jmx.adoc index d428877efa6..705566d71b0 100644 --- a/docs/user-manual/modules/ROOT/pages/jmx.adoc +++ b/docs/user-manual/modules/ROOT/pages/jmx.adoc @@ -133,9 +133,9 @@ MBeans are registered at startup. The levels are: * `ContextOnly` - Camel will register MBeans for the context (neither for any route nor for any processor). -=== Registering new MBeans for new routes or endpoints +=== Registering new MBeans for new routes, created by route templates, Kamelets -Camel provides two settings to control when to register mbeans. +Camel provides the following settings to control when to register mbeans. [width="100%",cols="34%,33%,33%",options="header",] |======================================================================= @@ -145,6 +145,11 @@ Camel provides two settings to control when to register mbeans. |`registerNewRoutes` |`true` |If enabled then adding new routes after CamelContext has been started will also register MBeans from that given route. + +|`registerRoutesCreateByKamelet` |`false` |If enabled then adding routes created by Kamelet will also register MBeans from that given route. + +|`registerRoutesCreateByTemplate` |`true` |If enabled then adding routes created by route template (not Kamelet, see option above) will also register MBeans from that given route. + |======================================================================= By default, Camel automatically registers MBeans for all routes configured at @@ -153,6 +158,12 @@ registered for new routes added later on. This feature can be disabled, for example, if you are adding and removing temporary routes that do not require management. +In *Camel 4.5* onwards there are additional options to configure whether routes created from route templates or Kamelets +should be registered as MBeans or not. By default, Kamelets are now disabled with the intention to regard a Kamelet +as a component, instead of a set of additional routes and processors MBeans that is essentially not needed for management +and monitoring. The option `registerRoutesCreateByKamelet` can be set to `true` to enable MBeans which is how Camel 4.4 or +older behaves. On the other hand routes created from route templates (not Kamelets) are default enabled. + CAUTION: However, be cautious when using the `registerAlways` option in conjunction with dynamic EIP patterns, such as the xref:components:eips:recipientList-eip.adoc[Recipient List], which have unique endpoints. This can potentially lead to system degradation