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 2c8368e3122c1..2d3a5c167116e 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 @@ -182,6 +182,7 @@ { "name": "camel.metrics.enableRouteEventNotifier", "description": "Set whether to enable the MicrometerRouteEventNotifier for capturing metrics on the total number of routes and total number of routes running.", "sourceType": "org.apache.camel.main.MetricsConfigurationProperties", "type": "boolean", "javaType": "boolean", "defaultValue": true }, { "name": "camel.metrics.enableRoutePolicy", "description": "Set whether to enable the MicrometerRoutePolicyFactory for capturing metrics on route processing times.", "sourceType": "org.apache.camel.main.MetricsConfigurationProperties", "type": "boolean", "javaType": "boolean", "defaultValue": true }, { "name": "camel.metrics.namingStrategy", "description": "Controls the name style to use for metrics. Default = uses micrometer naming convention. Legacy = uses the classic naming style (camelCase)", "sourceType": "org.apache.camel.main.MetricsConfigurationProperties", "type": "string", "javaType": "java.lang.String", "defaultValue": "default", "enum": [ "default", "legacy" ] }, + { "name": "camel.metrics.routePolicyLevel", "description": "Sets the level of information to capture. all = both context and routes.", "sourceType": "org.apache.camel.main.MetricsConfigurationProperties", "type": "string", "javaType": "java.lang.String", "defaultValue": "all", "enum": [ "all", "route", "context" ] }, { "name": "camel.metrics.textFormatVersion", "description": "The text-format version to use with Prometheus scraping. 0.0.4 = text\/plain; version=0.0.4; charset=utf-8 1.0.0 = application\/openmetrics-text; version=1.0.0; charset=utf-8", "sourceType": "org.apache.camel.main.MetricsConfigurationProperties", "type": "string", "javaType": "java.lang.String", "defaultValue": "0.0.4", "enum": [ "0.0.4", "1.0.0" ] }, { "name": "camel.opentelemetry.enabled", "description": "To enable OpenTelemetry", "sourceType": "org.apache.camel.main.OtelConfigurationProperties", "type": "boolean", "javaType": "boolean", "defaultValue": "false" }, { "name": "camel.opentelemetry.encoding", "description": "Sets whether the header keys need to be encoded (connector specific) or not. The value is a boolean. Dashes need for instances to be encoded for JMS property keys.", "sourceType": "org.apache.camel.main.OtelConfigurationProperties", "type": "boolean", "javaType": "boolean", "defaultValue": "false" }, diff --git a/components/camel-micrometer-prometheus/src/generated/java/org/apache/camel/component/micrometer/prometheus/MicrometerPrometheusConfigurer.java b/components/camel-micrometer-prometheus/src/generated/java/org/apache/camel/component/micrometer/prometheus/MicrometerPrometheusConfigurer.java index 3466314c9cd8d..211bcde62d79c 100644 --- a/components/camel-micrometer-prometheus/src/generated/java/org/apache/camel/component/micrometer/prometheus/MicrometerPrometheusConfigurer.java +++ b/components/camel-micrometer-prometheus/src/generated/java/org/apache/camel/component/micrometer/prometheus/MicrometerPrometheusConfigurer.java @@ -37,6 +37,8 @@ public boolean configure(CamelContext camelContext, Object obj, String name, Obj case "EnableRoutePolicy": target.setEnableRoutePolicy(property(camelContext, boolean.class, value)); return true; case "namingstrategy": case "NamingStrategy": target.setNamingStrategy(property(camelContext, java.lang.String.class, value)); return true; + case "routepolicylevel": + case "RoutePolicyLevel": target.setRoutePolicyLevel(property(camelContext, java.lang.String.class, value)); return true; case "textformatversion": case "TextFormatVersion": target.setTextFormatVersion(property(camelContext, java.lang.String.class, value)); return true; default: return false; @@ -62,6 +64,8 @@ public Class getOptionType(String name, boolean ignoreCase) { case "EnableRoutePolicy": return boolean.class; case "namingstrategy": case "NamingStrategy": return java.lang.String.class; + case "routepolicylevel": + case "RoutePolicyLevel": return java.lang.String.class; case "textformatversion": case "TextFormatVersion": return java.lang.String.class; default: return null; @@ -88,6 +92,8 @@ public Object getOptionValue(Object obj, String name, boolean ignoreCase) { case "EnableRoutePolicy": return target.isEnableRoutePolicy(); case "namingstrategy": case "NamingStrategy": return target.getNamingStrategy(); + case "routepolicylevel": + case "RoutePolicyLevel": return target.getRoutePolicyLevel(); case "textformatversion": case "TextFormatVersion": return target.getTextFormatVersion(); default: return null; diff --git a/components/camel-micrometer-prometheus/src/main/java/org/apache/camel/component/micrometer/prometheus/MicrometerPrometheus.java b/components/camel-micrometer-prometheus/src/main/java/org/apache/camel/component/micrometer/prometheus/MicrometerPrometheus.java index 5ef866cdf95a4..7174f6c0831dd 100644 --- a/components/camel-micrometer-prometheus/src/main/java/org/apache/camel/component/micrometer/prometheus/MicrometerPrometheus.java +++ b/components/camel-micrometer-prometheus/src/main/java/org/apache/camel/component/micrometer/prometheus/MicrometerPrometheus.java @@ -84,6 +84,8 @@ public class MicrometerPrometheus extends ServiceSupport implements CamelMetrics private String namingStrategy; @Metadata(defaultValue = "true") private boolean enableRoutePolicy = true; + @Metadata(defaultValue = "all", enums = "all,route,context") + private String routePolicyLevel = "all"; @Metadata(defaultValue = "false") private boolean enableMessageHistory; @Metadata(defaultValue = "true") @@ -131,6 +133,17 @@ public void setEnableRoutePolicy(boolean enableRoutePolicy) { this.enableRoutePolicy = enableRoutePolicy; } + public String getRoutePolicyLevel() { + return routePolicyLevel; + } + + /** + * Sets the level of information to capture. all = both context and routes. + */ + public void setRoutePolicyLevel(String routePolicyLevel) { + this.routePolicyLevel = routePolicyLevel; + } + public boolean isEnableMessageHistory() { return enableMessageHistory; } @@ -240,7 +253,19 @@ protected void doInit() throws Exception { if ("legacy".equalsIgnoreCase(namingStrategy)) { factory.setNamingStrategy(MicrometerRoutePolicyNamingStrategy.LEGACY); } + if ("all".equalsIgnoreCase(routePolicyLevel)) { + factory.getPolicyConfiguration().setContextEnabled(true); + factory.getPolicyConfiguration().setRouteEnabled(true); + } else if ("context".equalsIgnoreCase(routePolicyLevel)) { + factory.getPolicyConfiguration().setContextEnabled(true); + factory.getPolicyConfiguration().setRouteEnabled(false); + } else { + factory.getPolicyConfiguration().setContextEnabled(false); + factory.getPolicyConfiguration().setRouteEnabled(true); + } factory.setMeterRegistry(meterRegistry); + // ensure factory will be started and stopped + camelContext.addService(factory); camelContext.addRoutePolicyFactory(factory); } diff --git a/components/camel-micrometer/src/main/docs/micrometer-component.adoc b/components/camel-micrometer/src/main/docs/micrometer-component.adoc index b296a54dd9eb8..45a0540c927de 100644 --- a/components/camel-micrometer/src/main/docs/micrometer-component.adoc +++ b/components/camel-micrometer/src/main/docs/micrometer-component.adoc @@ -407,6 +407,8 @@ following options: [width="100%",options="header"] |======================================================================= |Name |Default |Description +|contextEnabled | true | whether to include counter for context level metrics +|routeEnabled | true | whether to include counter for route level metrics |additionalCounters | true | activates all additional counters |exchangesSucceeded | true | activates counter for succeeded exchanges |exchangesFailed | true | activates counter for failed exchanges diff --git a/components/camel-micrometer/src/main/java/org/apache/camel/component/micrometer/json/AbstractMicrometerService.java b/components/camel-micrometer/src/main/java/org/apache/camel/component/micrometer/json/AbstractMicrometerService.java index fcfff985ca345..574cd8bf596c6 100644 --- a/components/camel-micrometer/src/main/java/org/apache/camel/component/micrometer/json/AbstractMicrometerService.java +++ b/components/camel-micrometer/src/main/java/org/apache/camel/component/micrometer/json/AbstractMicrometerService.java @@ -137,6 +137,6 @@ protected void doStart() { @Override protected void doStop() { - + // noop } } diff --git a/components/camel-micrometer/src/main/java/org/apache/camel/component/micrometer/routepolicy/ContextMetricsStatistics.java b/components/camel-micrometer/src/main/java/org/apache/camel/component/micrometer/routepolicy/ContextMetricsStatistics.java new file mode 100644 index 0000000000000..1e39d8d683abf --- /dev/null +++ b/components/camel-micrometer/src/main/java/org/apache/camel/component/micrometer/routepolicy/ContextMetricsStatistics.java @@ -0,0 +1,71 @@ +/* + * 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.micrometer.routepolicy; + +import io.micrometer.core.instrument.MeterRegistry; +import org.apache.camel.CamelContext; +import org.apache.camel.Exchange; +import org.apache.camel.spi.UnitOfWork; + +final class ContextMetricsStatistics extends MicrometerRoutePolicy.MetricsStatistics { + + private final boolean registerKamelets; + private final boolean registerTemplates; + + ContextMetricsStatistics(MeterRegistry meterRegistry, CamelContext camelContext, + MicrometerRoutePolicyNamingStrategy namingStrategy, + MicrometerRoutePolicyConfiguration configuration, boolean registerKamelets, + boolean registerTemplates) { + super(meterRegistry, camelContext, null, namingStrategy, configuration); + this.registerKamelets = registerKamelets; + this.registerTemplates = registerTemplates; + } + + @Override + public void onExchangeBegin(Exchange exchange) { + // this metric is triggered for every route + // so we must only trigger on the root level, otherwise this metric + // 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(registerTemplates, registerKamelets); + if (level <= 1) { + super.onExchangeBegin(exchange); + } + } else { + super.onExchangeBegin(exchange); + } + } + + @Override + public void onExchangeDone(Exchange exchange) { + // this metric is triggered for every route + // so we must only trigger on the root level, otherwise this metric + // 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(registerTemplates, registerKamelets); + if (level <= 1) { + super.onExchangeDone(exchange); + } + } else { + super.onExchangeDone(exchange); + } + } +} 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 74681d8797dd2..7df31be65bdad 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 @@ -26,6 +26,7 @@ import io.micrometer.core.instrument.MeterRegistry; import io.micrometer.core.instrument.Tags; import io.micrometer.core.instrument.Timer; +import org.apache.camel.CamelContext; import org.apache.camel.Exchange; import org.apache.camel.NonManagedService; import org.apache.camel.Route; @@ -48,6 +49,7 @@ */ public class MicrometerRoutePolicy extends RoutePolicySupport implements NonManagedService { + private final MicrometerRoutePolicyFactory factory; private MeterRegistry meterRegistry; private boolean prettyPrint; private TimeUnit durationUnit = TimeUnit.MILLISECONDS; @@ -55,11 +57,13 @@ public class MicrometerRoutePolicy extends RoutePolicySupport implements NonMana private MicrometerRoutePolicyConfiguration configuration = MicrometerRoutePolicyConfiguration.DEFAULT; private final Map statisticsMap = new HashMap<>(); + private RouteMetric contextStatistic; boolean registerKamelets; boolean registerTemplates = true; - private static final class MetricsStatistics { + static class MetricsStatistics implements RouteMetric { private final MeterRegistry meterRegistry; + private final CamelContext camelContext; private final Route route; private final MicrometerRoutePolicyNamingStrategy namingStrategy; private final MicrometerRoutePolicyConfiguration configuration; @@ -71,12 +75,13 @@ private static final class MetricsStatistics { private Timer timer; private LongTaskTimer longTaskTimer; - private MetricsStatistics(MeterRegistry meterRegistry, Route route, - MicrometerRoutePolicyNamingStrategy namingStrategy, - MicrometerRoutePolicyConfiguration configuration) { + MetricsStatistics(MeterRegistry meterRegistry, CamelContext camelContext, Route route, + MicrometerRoutePolicyNamingStrategy namingStrategy, + MicrometerRoutePolicyConfiguration configuration) { this.configuration = ObjectHelper.notNull(configuration, "MicrometerRoutePolicyConfiguration", this); this.meterRegistry = ObjectHelper.notNull(meterRegistry, "MeterRegistry", this); this.namingStrategy = ObjectHelper.notNull(namingStrategy, "MicrometerRoutePolicyNamingStrategy", this); + this.camelContext = camelContext; this.route = route; if (configuration.isAdditionalCounters()) { initAdditionalCounters(); @@ -106,8 +111,8 @@ private void initAdditionalCounters() { } if (configuration.isLongTask()) { LongTaskTimer.Builder builder = LongTaskTimer.builder(namingStrategy.getLongTaskName(route)) - .tags(namingStrategy.getTags(route)) - .description("Route long task metric"); + .tags(route != null ? namingStrategy.getTags(route) : namingStrategy.getTags(camelContext)) + .description(route != null ? "Route long task metric" : "CamelContext long task metric"); if (configuration.getLongTaskInitiator() != null) { configuration.getLongTaskInitiator().accept(builder); } @@ -128,8 +133,8 @@ public void onExchangeDone(Exchange exchange) { if (sample != null) { if (timer == null) { Timer.Builder builder = Timer.builder(namingStrategy.getName(route)) - .tags(namingStrategy.getTags(route)) - .description("Route performance metrics"); + .tags(route != null ? namingStrategy.getTags(route) : namingStrategy.getTags(camelContext)) + .description(route != null ? "Route performance metrics" : "CamelContext performance metrics"); if (configuration.getTimerInitiator() != null) { configuration.getTimerInitiator().accept(builder); } @@ -147,6 +152,30 @@ public void onExchangeDone(Exchange exchange) { } } + public void remove() { + if (exchangesSucceeded != null) { + meterRegistry.remove(exchangesSucceeded); + } + if (exchangesFailed != null) { + meterRegistry.remove(exchangesFailed); + } + if (exchangesTotal != null) { + meterRegistry.remove(exchangesTotal); + } + if (externalRedeliveries != null) { + meterRegistry.remove(externalRedeliveries); + } + if (failuresHandled != null) { + meterRegistry.remove(failuresHandled); + } + if (timer != null) { + meterRegistry.remove(timer); + } + if (longTaskTimer != null) { + meterRegistry.remove(longTaskTimer); + } + } + private void updateAdditionalCounters(Exchange exchange) { if (exchangesTotal != null) { exchangesTotal.increment(); @@ -169,17 +198,32 @@ private void updateAdditionalCounters(Exchange exchange) { } private String propertyName(Exchange exchange) { - return String.format("%s-%s-%s", DEFAULT_CAMEL_ROUTE_POLICY_METER_NAME, route.getId(), exchange.getExchangeId()); + String id; + if (route != null) { + id = route.getId(); + } else { + id = "context:" + camelContext.getName(); + } + return String.format("%s-%s-%s", DEFAULT_CAMEL_ROUTE_POLICY_METER_NAME, id, exchange.getExchangeId()); } private Counter createCounter(String meterName, String description) { return Counter.builder(meterName) - .tags(namingStrategy.getExchangeStatusTags(route)) + .tags(route != null + ? namingStrategy.getExchangeStatusTags(route) : namingStrategy.getExchangeStatusTags(camelContext)) .description(description) .register(meterRegistry); } } + public MicrometerRoutePolicy() { + this.factory = null; + } + + public MicrometerRoutePolicy(MicrometerRoutePolicyFactory factory) { + this.factory = factory; + } + public MeterRegistry getMeterRegistry() { return meterRegistry; } @@ -249,6 +293,18 @@ public void onInit(Route route) { } catch (Exception e) { throw RuntimeCamelException.wrapRuntimeCamelException(e); } + + if (factory != null && configuration.isContextEnabled() && contextStatistic == null) { + contextStatistic = factory.createOrGetContextMetric(this); + } + } + + boolean isRegisterKamelets() { + return registerKamelets; + } + + boolean isRegisterTemplates() { + return registerTemplates; } @Override @@ -258,13 +314,17 @@ public void onStart(Route route) { // we have in-flight / total statistics already from camel-core statisticsMap.computeIfAbsent(route, it -> { + boolean skip = !configuration.isRouteEnabled(); // skip routes that should not be included - boolean skip = (it.isCreatedByKamelet() && !registerKamelets) - || (it.isCreatedByRouteTemplate() && !registerTemplates); + if (!skip) { + skip = (it.isCreatedByKamelet() && !registerKamelets) + || (it.isCreatedByRouteTemplate() && !registerTemplates); + } if (skip) { return null; } - return new MetricsStatistics(getMeterRegistry(), it, getNamingStrategy(), configuration); + return new MetricsStatistics( + getMeterRegistry(), it.getCamelContext(), it, getNamingStrategy(), configuration); }); } @@ -273,38 +333,24 @@ public void onRemove(Route route) { // route is removed, so remove metrics from micrometer MetricsStatistics stats = statisticsMap.remove(route); if (stats != null) { - if (stats.exchangesSucceeded != null) { - meterRegistry.remove(stats.exchangesSucceeded); - } - if (stats.exchangesFailed != null) { - meterRegistry.remove(stats.exchangesFailed); - } - if (stats.exchangesTotal != null) { - meterRegistry.remove(stats.exchangesTotal); - } - if (stats.externalRedeliveries != null) { - meterRegistry.remove(stats.externalRedeliveries); - } - if (stats.failuresHandled != null) { - meterRegistry.remove(stats.failuresHandled); - } - if (stats.timer != null) { - meterRegistry.remove(stats.timer); - } - if (stats.longTaskTimer != null) { - meterRegistry.remove(stats.longTaskTimer); - } + stats.remove(); } } @Override public void onExchangeBegin(Route route, Exchange exchange) { + if (contextStatistic != null) { + contextStatistic.onExchangeBegin(exchange); + } Optional.ofNullable(statisticsMap.get(route)) .ifPresent(statistics -> statistics.onExchangeBegin(exchange)); } @Override public void onExchangeDone(Route route, Exchange exchange) { + if (contextStatistic != null) { + contextStatistic.onExchangeDone(exchange); + } Optional.ofNullable(statisticsMap.get(route)) .ifPresent(statistics -> statistics.onExchangeDone(exchange)); } diff --git a/components/camel-micrometer/src/main/java/org/apache/camel/component/micrometer/routepolicy/MicrometerRoutePolicyConfiguration.java b/components/camel-micrometer/src/main/java/org/apache/camel/component/micrometer/routepolicy/MicrometerRoutePolicyConfiguration.java index 1c1f57966e510..6b1f9eca8be7d 100644 --- a/components/camel-micrometer/src/main/java/org/apache/camel/component/micrometer/routepolicy/MicrometerRoutePolicyConfiguration.java +++ b/components/camel-micrometer/src/main/java/org/apache/camel/component/micrometer/routepolicy/MicrometerRoutePolicyConfiguration.java @@ -23,6 +23,8 @@ public class MicrometerRoutePolicyConfiguration { public static final MicrometerRoutePolicyConfiguration DEFAULT = new MicrometerRoutePolicyConfiguration(); + private boolean contextEnabled = true; + private boolean routeEnabled = true; private boolean additionalCounters = true; private boolean exchangesSucceeded = true; private boolean exchangesFailed = true; @@ -33,6 +35,22 @@ public class MicrometerRoutePolicyConfiguration { private Consumer timerInitiator; private Consumer longTaskInitiator; + public boolean isContextEnabled() { + return contextEnabled; + } + + public void setContextEnabled(boolean contextEnabled) { + this.contextEnabled = contextEnabled; + } + + public boolean isRouteEnabled() { + return routeEnabled; + } + + public void setRouteEnabled(boolean routeEnabled) { + this.routeEnabled = routeEnabled; + } + public boolean isAdditionalCounters() { return additionalCounters; } diff --git a/components/camel-micrometer/src/main/java/org/apache/camel/component/micrometer/routepolicy/MicrometerRoutePolicyFactory.java b/components/camel-micrometer/src/main/java/org/apache/camel/component/micrometer/routepolicy/MicrometerRoutePolicyFactory.java index dde82239a9ffb..446b1de803431 100644 --- a/components/camel-micrometer/src/main/java/org/apache/camel/component/micrometer/routepolicy/MicrometerRoutePolicyFactory.java +++ b/components/camel-micrometer/src/main/java/org/apache/camel/component/micrometer/routepolicy/MicrometerRoutePolicyFactory.java @@ -20,22 +20,39 @@ import io.micrometer.core.instrument.MeterRegistry; import org.apache.camel.CamelContext; +import org.apache.camel.CamelContextAware; import org.apache.camel.NamedNode; +import org.apache.camel.NonManagedService; +import org.apache.camel.StaticService; import org.apache.camel.spi.RoutePolicy; import org.apache.camel.spi.RoutePolicyFactory; +import org.apache.camel.support.service.ServiceSupport; /** * A {@link org.apache.camel.spi.RoutePolicyFactory} to plugin and use metrics for gathering route utilization * statistics */ -public class MicrometerRoutePolicyFactory implements RoutePolicyFactory { +public class MicrometerRoutePolicyFactory extends ServiceSupport + implements RoutePolicyFactory, CamelContextAware, NonManagedService, StaticService { + private CamelContext camelContext; private MeterRegistry meterRegistry; + private RouteMetric contextMetric; private boolean prettyPrint = true; private TimeUnit durationUnit = TimeUnit.MILLISECONDS; private MicrometerRoutePolicyNamingStrategy namingStrategy = MicrometerRoutePolicyNamingStrategy.DEFAULT; private MicrometerRoutePolicyConfiguration policyConfiguration = MicrometerRoutePolicyConfiguration.DEFAULT; + @Override + public CamelContext getCamelContext() { + return camelContext; + } + + @Override + public void setCamelContext(CamelContext camelContext) { + this.camelContext = camelContext; + } + /** * To use a specific {@link io.micrometer.core.instrument.MeterRegistry} instance. *

@@ -90,9 +107,19 @@ public void setPolicyConfiguration(MicrometerRoutePolicyConfiguration policyConf this.policyConfiguration = policyConfiguration; } + public RouteMetric createOrGetContextMetric(MicrometerRoutePolicy policy) { + if (contextMetric == null) { + contextMetric = new ContextMetricsStatistics( + policy.getMeterRegistry(), camelContext, + policy.getNamingStrategy(), policy.getConfiguration(), + policy.isRegisterKamelets(), policy.isRegisterTemplates()); + } + return contextMetric; + } + @Override public RoutePolicy createRoutePolicy(CamelContext camelContext, String routeId, NamedNode routeDefinition) { - MicrometerRoutePolicy answer = new MicrometerRoutePolicy(); + MicrometerRoutePolicy answer = new MicrometerRoutePolicy(this); answer.setMeterRegistry(getMeterRegistry()); answer.setPrettyPrint(isPrettyPrint()); answer.setDurationUnit(getDurationUnit()); @@ -101,4 +128,12 @@ public RoutePolicy createRoutePolicy(CamelContext camelContext, String routeId, return answer; } + @Override + protected void doShutdown() throws Exception { + super.doShutdown(); + if (contextMetric != null) { + contextMetric.remove(); + contextMetric = null; + } + } } diff --git a/components/camel-micrometer/src/main/java/org/apache/camel/component/micrometer/routepolicy/MicrometerRoutePolicyNamingStrategy.java b/components/camel-micrometer/src/main/java/org/apache/camel/component/micrometer/routepolicy/MicrometerRoutePolicyNamingStrategy.java index f3e05e5e534e5..3ec3d138897ab 100644 --- a/components/camel-micrometer/src/main/java/org/apache/camel/component/micrometer/routepolicy/MicrometerRoutePolicyNamingStrategy.java +++ b/components/camel-micrometer/src/main/java/org/apache/camel/component/micrometer/routepolicy/MicrometerRoutePolicyNamingStrategy.java @@ -20,6 +20,7 @@ import io.micrometer.core.instrument.Meter; import io.micrometer.core.instrument.Tags; +import org.apache.camel.CamelContext; import org.apache.camel.Route; import org.apache.camel.component.micrometer.MicrometerUtils; @@ -87,13 +88,31 @@ default Tags getTags(Route route) { return Tags.of( CAMEL_CONTEXT_TAG, route.getCamelContext().getName(), SERVICE_NAME, MicrometerRoutePolicyService.class.getSimpleName(), - ROUTE_ID_TAG, route.getId()); + ROUTE_ID_TAG, route.getId(), + EVENT_TYPE_TAG, "route"); + } + + default Tags getTags(CamelContext camelContext) { + return Tags.of( + CAMEL_CONTEXT_TAG, camelContext.getName(), + SERVICE_NAME, MicrometerRoutePolicyService.class.getSimpleName(), + ROUTE_ID_TAG, "", + EVENT_TYPE_TAG, "context"); } default Tags getExchangeStatusTags(Route route) { return Tags.of( CAMEL_CONTEXT_TAG, route.getCamelContext().getName(), SERVICE_NAME, MicrometerRoutePolicyService.class.getSimpleName(), - ROUTE_ID_TAG, route.getId()); + ROUTE_ID_TAG, route.getId(), + EVENT_TYPE_TAG, "route"); + } + + default Tags getExchangeStatusTags(CamelContext camelContext) { + return Tags.of( + CAMEL_CONTEXT_TAG, camelContext.getName(), + SERVICE_NAME, MicrometerRoutePolicyService.class.getSimpleName(), + ROUTE_ID_TAG, "", + EVENT_TYPE_TAG, "context"); } } diff --git a/components/camel-micrometer/src/main/java/org/apache/camel/component/micrometer/routepolicy/RouteMetric.java b/components/camel-micrometer/src/main/java/org/apache/camel/component/micrometer/routepolicy/RouteMetric.java new file mode 100644 index 0000000000000..89d0b1f5cc9f5 --- /dev/null +++ b/components/camel-micrometer/src/main/java/org/apache/camel/component/micrometer/routepolicy/RouteMetric.java @@ -0,0 +1,29 @@ +/* + * 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.micrometer.routepolicy; + +import org.apache.camel.Exchange; + +public interface RouteMetric { + + void onExchangeBegin(Exchange exchange); + + void onExchangeDone(Exchange exchange); + + void remove(); + +} diff --git a/components/camel-micrometer/src/test/java/org/apache/camel/component/micrometer/messagehistory/ManagedMessageHistoryTest.java b/components/camel-micrometer/src/test/java/org/apache/camel/component/micrometer/messagehistory/ManagedMessageHistoryTest.java index 7125f9d5ab8a7..030b6a6cd080e 100644 --- a/components/camel-micrometer/src/test/java/org/apache/camel/component/micrometer/messagehistory/ManagedMessageHistoryTest.java +++ b/components/camel-micrometer/src/test/java/org/apache/camel/component/micrometer/messagehistory/ManagedMessageHistoryTest.java @@ -63,6 +63,16 @@ public void addRegistry() { meterRegistry.add(new JmxMeterRegistry(CamelJmxConfig.DEFAULT, Clock.SYSTEM, HierarchicalNameMapper.DEFAULT)); } + @Override + public void tearDown() throws Exception { + super.tearDown(); + if (meterRegistry != null) { + meterRegistry.clear(); + meterRegistry.close(); + meterRegistry = null; + } + } + @Override protected CamelContext createCamelContext() throws Exception { CamelContext context = super.createCamelContext(); @@ -71,7 +81,6 @@ protected CamelContext createCamelContext() throws Exception { factory.setPrettyPrint(true); factory.setMeterRegistry(meterRegistry); context.setMessageHistoryFactory(factory); - return context; } diff --git a/components/camel-micrometer/src/test/java/org/apache/camel/component/micrometer/routepolicy/AbstractMicrometerRoutePolicyTest.java b/components/camel-micrometer/src/test/java/org/apache/camel/component/micrometer/routepolicy/AbstractMicrometerRoutePolicyTest.java index feb1dd369c570..a144ce2b24afc 100644 --- a/components/camel-micrometer/src/test/java/org/apache/camel/component/micrometer/routepolicy/AbstractMicrometerRoutePolicyTest.java +++ b/components/camel-micrometer/src/test/java/org/apache/camel/component/micrometer/routepolicy/AbstractMicrometerRoutePolicyTest.java @@ -16,15 +16,11 @@ */ package org.apache.camel.component.micrometer.routepolicy; -import io.micrometer.core.instrument.Clock; -import io.micrometer.core.instrument.composite.CompositeMeterRegistry; +import io.micrometer.core.instrument.MeterRegistry; import io.micrometer.core.instrument.simple.SimpleMeterRegistry; -import io.micrometer.core.instrument.util.HierarchicalNameMapper; -import io.micrometer.jmx.JmxMeterRegistry; -import org.apache.camel.BindToRegistry; import org.apache.camel.CamelContext; -import org.apache.camel.component.micrometer.CamelJmxConfig; import org.apache.camel.component.micrometer.MicrometerConstants; +import org.apache.camel.support.LifecycleStrategySupport; import org.apache.camel.test.junit5.CamelTestSupport; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -32,23 +28,22 @@ public abstract class AbstractMicrometerRoutePolicyTest extends CamelTestSupport { protected final Logger log = LoggerFactory.getLogger(getClass()); - protected CompositeMeterRegistry meterRegistry; + protected MeterRegistry meterRegistry; - @Override - protected boolean useJmx() { - return true; - } - - @BindToRegistry(MicrometerConstants.METRICS_REGISTRY_NAME) - public CompositeMeterRegistry addRegistry() { - meterRegistry = new CompositeMeterRegistry(); - meterRegistry.add(new SimpleMeterRegistry()); - meterRegistry.add(new JmxMeterRegistry(CamelJmxConfig.DEFAULT, Clock.SYSTEM, HierarchicalNameMapper.DEFAULT)); - return meterRegistry; + protected MicrometerRoutePolicyFactory createMicrometerRoutePolicyFactory() { + MicrometerRoutePolicyFactory factory = new MicrometerRoutePolicyFactory(); + factory.getPolicyConfiguration().setContextEnabled(false); + return factory; } - protected MicrometerRoutePolicyFactory createMicrometerRoutePolicyFactory() { - return new MicrometerRoutePolicyFactory(); + @Override + public void tearDown() throws Exception { + super.tearDown(); + if (meterRegistry != null) { + meterRegistry.clear(); + meterRegistry.close(); + meterRegistry = null; + } } protected String formatMetricName(String name) { @@ -57,10 +52,25 @@ protected String formatMetricName(String name) { @Override protected CamelContext createCamelContext() throws Exception { + meterRegistry = new SimpleMeterRegistry(); CamelContext context = super.createCamelContext(); MicrometerRoutePolicyFactory factory = createMicrometerRoutePolicyFactory(); + factory.setCamelContext(context); factory.setMeterRegistry(meterRegistry); context.addRoutePolicyFactory(factory); + context.getRegistry().bind(MicrometerConstants.METRICS_REGISTRY_NAME, meterRegistry); + context.addService(factory); + // TODO: CAMEL-20522 + context.addLifecycleStrategy(new LifecycleStrategySupport() { + @Override + public void onContextStopped(CamelContext context) { + if (meterRegistry != null) { + meterRegistry.clear(); + meterRegistry.close(); + meterRegistry = null; + } + } + }); return context; } diff --git a/components/camel-micrometer/src/test/java/org/apache/camel/component/micrometer/routepolicy/LegacyMicrometerRoutePolicyTest.java b/components/camel-micrometer/src/test/java/org/apache/camel/component/micrometer/routepolicy/LegacyMicrometerRoutePolicyTest.java index f3989e47bd2aa..ed49b797a4197 100644 --- a/components/camel-micrometer/src/test/java/org/apache/camel/component/micrometer/routepolicy/LegacyMicrometerRoutePolicyTest.java +++ b/components/camel-micrometer/src/test/java/org/apache/camel/component/micrometer/routepolicy/LegacyMicrometerRoutePolicyTest.java @@ -26,6 +26,7 @@ public class LegacyMicrometerRoutePolicyTest extends MicrometerRoutePolicyTest { @Override protected MicrometerRoutePolicyFactory createMicrometerRoutePolicyFactory() { MicrometerRoutePolicyFactory factory = new MicrometerRoutePolicyFactory(); + factory.getPolicyConfiguration().setContextEnabled(false); factory.setNamingStrategy(MicrometerRoutePolicyNamingStrategy.LEGACY); return factory; } diff --git a/components/camel-micrometer/src/test/java/org/apache/camel/component/micrometer/routepolicy/ManagedMicrometerRoutePolicyTest.java b/components/camel-micrometer/src/test/java/org/apache/camel/component/micrometer/routepolicy/ManagedMicrometerRoutePolicyTest.java index 634ce9158199f..399655f58d08b 100644 --- a/components/camel-micrometer/src/test/java/org/apache/camel/component/micrometer/routepolicy/ManagedMicrometerRoutePolicyTest.java +++ b/components/camel-micrometer/src/test/java/org/apache/camel/component/micrometer/routepolicy/ManagedMicrometerRoutePolicyTest.java @@ -33,6 +33,11 @@ public class ManagedMicrometerRoutePolicyTest extends AbstractMicrometerRoutePolicyTest { + @Override + protected boolean useJmx() { + return true; + } + protected MBeanServer getMBeanServer() { return context.getManagementStrategy().getManagementAgent().getMBeanServer(); } diff --git a/components/camel-micrometer/src/test/java/org/apache/camel/component/micrometer/routepolicy/MicrometerContextPolicyTest.java b/components/camel-micrometer/src/test/java/org/apache/camel/component/micrometer/routepolicy/MicrometerContextPolicyTest.java new file mode 100644 index 0000000000000..5ed646ffd702b --- /dev/null +++ b/components/camel-micrometer/src/test/java/org/apache/camel/component/micrometer/routepolicy/MicrometerContextPolicyTest.java @@ -0,0 +1,77 @@ +/* + * 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.micrometer.routepolicy; + +import io.micrometer.core.instrument.Timer; +import org.apache.camel.builder.RouteBuilder; +import org.apache.camel.component.mock.MockEndpoint; +import org.junit.jupiter.api.Test; + +import static org.apache.camel.component.micrometer.MicrometerConstants.DEFAULT_CAMEL_ROUTE_POLICY_METER_NAME; +import static org.apache.camel.component.micrometer.MicrometerConstants.EVENT_TYPE_TAG; +import static org.junit.jupiter.api.Assertions.assertEquals; + +public class MicrometerContextPolicyTest extends AbstractMicrometerRoutePolicyTest { + + private static final long DELAY_FOO = 20; + private static final long DELAY_BAR = 50; + + @Override + protected MicrometerRoutePolicyFactory createMicrometerRoutePolicyFactory() { + MicrometerRoutePolicyFactory factory = super.createMicrometerRoutePolicyFactory(); + factory.getPolicyConfiguration().setContextEnabled(true); + return factory; + } + + @Test + public void testMetricsRoutePolicy() throws Exception { + int count = 10; + MockEndpoint mockEndpoint = getMockEndpoint("mock:result"); + mockEndpoint.expectedMessageCount(count); + + for (int i = 0; i < count; i++) { + if (i % 2 == 0) { + template.sendBody("direct:foo", "Hello " + i); + } else { + template.sendBody("direct:bar", "Hello " + i); + } + } + + MockEndpoint.assertIsSatisfied(context); + + Timer contextTimer + = meterRegistry.find(formatMetricName(DEFAULT_CAMEL_ROUTE_POLICY_METER_NAME)).tag(EVENT_TYPE_TAG, "context") + .timer(); + assertEquals(count, contextTimer.count()); + } + + @Override + protected RouteBuilder createRouteBuilder() { + return new RouteBuilder() { + @Override + public void configure() { + from("direct:foo").routeId("foo") + .delay(DELAY_FOO) + .to("mock:result"); + + from("direct:bar").routeId("bar") + .delay(DELAY_BAR) + .to("mock:result"); + } + }; + } +} diff --git a/components/camel-micrometer/src/test/java/org/apache/camel/component/micrometer/routepolicy/MicrometerRoutePolicyConfigrationTest.java b/components/camel-micrometer/src/test/java/org/apache/camel/component/micrometer/routepolicy/MicrometerRoutePolicyConfigrationTest.java index db6d8d05aebd4..a408b84862d6c 100644 --- a/components/camel-micrometer/src/test/java/org/apache/camel/component/micrometer/routepolicy/MicrometerRoutePolicyConfigrationTest.java +++ b/components/camel-micrometer/src/test/java/org/apache/camel/component/micrometer/routepolicy/MicrometerRoutePolicyConfigrationTest.java @@ -32,6 +32,7 @@ public class MicrometerRoutePolicyConfigrationTest extends AbstractMicrometerRou protected MicrometerRoutePolicyFactory createMicrometerRoutePolicyFactory() { MicrometerRoutePolicyFactory factory = new MicrometerRoutePolicyFactory(); MicrometerRoutePolicyConfiguration policyConfiguration = new MicrometerRoutePolicyConfiguration(); + policyConfiguration.setContextEnabled(false); policyConfiguration.setExchangesSucceeded(false); policyConfiguration.setExchangesFailed(false); policyConfiguration.setExchangesTotal(false); diff --git a/components/camel-micrometer/src/test/java/org/apache/camel/component/micrometer/routepolicy/SharedMicrometerRoutePolicyTest.java b/components/camel-micrometer/src/test/java/org/apache/camel/component/micrometer/routepolicy/SharedMicrometerRoutePolicyTest.java index 966382beb4851..536b82204de48 100644 --- a/components/camel-micrometer/src/test/java/org/apache/camel/component/micrometer/routepolicy/SharedMicrometerRoutePolicyTest.java +++ b/components/camel-micrometer/src/test/java/org/apache/camel/component/micrometer/routepolicy/SharedMicrometerRoutePolicyTest.java @@ -34,7 +34,7 @@ public class SharedMicrometerRoutePolicyTest extends CamelTestSupport { protected MeterRegistry meterRegistry = new SimpleMeterRegistry(); - protected MicrometerRoutePolicy singletonPolicy = new MicrometerRoutePolicy(); + protected MicrometerRoutePolicy singletonPolicy = new MicrometerRoutePolicy(null); @Test public void testSharedPolicy() throws Exception { diff --git a/components/camel-micrometer/src/test/java/org/apache/camel/component/micrometer/routepolicy/ZMicrometerContextOnlyPolicyTest.java b/components/camel-micrometer/src/test/java/org/apache/camel/component/micrometer/routepolicy/ZMicrometerContextOnlyPolicyTest.java new file mode 100644 index 0000000000000..87941faddb4e8 --- /dev/null +++ b/components/camel-micrometer/src/test/java/org/apache/camel/component/micrometer/routepolicy/ZMicrometerContextOnlyPolicyTest.java @@ -0,0 +1,81 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.camel.component.micrometer.routepolicy; + +import io.micrometer.core.instrument.Timer; +import org.apache.camel.builder.RouteBuilder; +import org.apache.camel.component.mock.MockEndpoint; +import org.junit.jupiter.api.Test; + +import static org.apache.camel.component.micrometer.MicrometerConstants.DEFAULT_CAMEL_ROUTE_POLICY_METER_NAME; +import static org.apache.camel.component.micrometer.MicrometerConstants.EVENT_TYPE_TAG; +import static org.junit.jupiter.api.Assertions.assertEquals; + +/** + * Must run last + */ +public class ZMicrometerContextOnlyPolicyTest extends AbstractMicrometerRoutePolicyTest { + + private static final long DELAY_FOO = 20; + private static final long DELAY_BAR = 50; + + @Override + protected MicrometerRoutePolicyFactory createMicrometerRoutePolicyFactory() { + MicrometerRoutePolicyFactory factory = super.createMicrometerRoutePolicyFactory(); + factory.getPolicyConfiguration().setContextEnabled(true); + factory.getPolicyConfiguration().setRouteEnabled(false); + return factory; + } + + @Test + public void testMetricsRoutePolicy() throws Exception { + int count = 10; + MockEndpoint mockEndpoint = getMockEndpoint("mock:result"); + mockEndpoint.expectedMessageCount(count); + + for (int i = 0; i < count; i++) { + if (i % 2 == 0) { + template.sendBody("direct:foo", "Hello " + i); + } else { + template.sendBody("direct:bar", "Hello " + i); + } + } + + MockEndpoint.assertIsSatisfied(context); + + Timer contextTimer + = meterRegistry.find(formatMetricName(DEFAULT_CAMEL_ROUTE_POLICY_METER_NAME)).tag(EVENT_TYPE_TAG, "context") + .timer(); + assertEquals(count, contextTimer.count()); + } + + @Override + protected RouteBuilder createRouteBuilder() { + return new RouteBuilder() { + @Override + public void configure() { + from("direct:foo").routeId("foo") + .delay(DELAY_FOO) + .to("mock:result"); + + from("direct:bar").routeId("bar") + .delay(DELAY_BAR) + .to("mock:result"); + } + }; + } +} diff --git a/core/camel-main/src/generated/java/org/apache/camel/main/MetricsConfigurationPropertiesConfigurer.java b/core/camel-main/src/generated/java/org/apache/camel/main/MetricsConfigurationPropertiesConfigurer.java index 59fd581efe086..a035e5cc26c3c 100644 --- a/core/camel-main/src/generated/java/org/apache/camel/main/MetricsConfigurationPropertiesConfigurer.java +++ b/core/camel-main/src/generated/java/org/apache/camel/main/MetricsConfigurationPropertiesConfigurer.java @@ -37,6 +37,8 @@ public boolean configure(CamelContext camelContext, Object obj, String name, Obj case "Enabled": target.setEnabled(property(camelContext, boolean.class, value)); return true; case "namingstrategy": case "NamingStrategy": target.setNamingStrategy(property(camelContext, java.lang.String.class, value)); return true; + case "routepolicylevel": + case "RoutePolicyLevel": target.setRoutePolicyLevel(property(camelContext, java.lang.String.class, value)); return true; case "textformatversion": case "TextFormatVersion": target.setTextFormatVersion(property(camelContext, java.lang.String.class, value)); return true; default: return false; @@ -62,6 +64,8 @@ public Class getOptionType(String name, boolean ignoreCase) { case "Enabled": return boolean.class; case "namingstrategy": case "NamingStrategy": return java.lang.String.class; + case "routepolicylevel": + case "RoutePolicyLevel": return java.lang.String.class; case "textformatversion": case "TextFormatVersion": return java.lang.String.class; default: return null; @@ -88,6 +92,8 @@ public Object getOptionValue(Object obj, String name, boolean ignoreCase) { case "Enabled": return target.isEnabled(); case "namingstrategy": case "NamingStrategy": return target.getNamingStrategy(); + case "routepolicylevel": + case "RoutePolicyLevel": return target.getRoutePolicyLevel(); case "textformatversion": case "TextFormatVersion": return target.getTextFormatVersion(); default: return null; 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 2c8368e3122c1..2d3a5c167116e 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 @@ -182,6 +182,7 @@ { "name": "camel.metrics.enableRouteEventNotifier", "description": "Set whether to enable the MicrometerRouteEventNotifier for capturing metrics on the total number of routes and total number of routes running.", "sourceType": "org.apache.camel.main.MetricsConfigurationProperties", "type": "boolean", "javaType": "boolean", "defaultValue": true }, { "name": "camel.metrics.enableRoutePolicy", "description": "Set whether to enable the MicrometerRoutePolicyFactory for capturing metrics on route processing times.", "sourceType": "org.apache.camel.main.MetricsConfigurationProperties", "type": "boolean", "javaType": "boolean", "defaultValue": true }, { "name": "camel.metrics.namingStrategy", "description": "Controls the name style to use for metrics. Default = uses micrometer naming convention. Legacy = uses the classic naming style (camelCase)", "sourceType": "org.apache.camel.main.MetricsConfigurationProperties", "type": "string", "javaType": "java.lang.String", "defaultValue": "default", "enum": [ "default", "legacy" ] }, + { "name": "camel.metrics.routePolicyLevel", "description": "Sets the level of information to capture. all = both context and routes.", "sourceType": "org.apache.camel.main.MetricsConfigurationProperties", "type": "string", "javaType": "java.lang.String", "defaultValue": "all", "enum": [ "all", "route", "context" ] }, { "name": "camel.metrics.textFormatVersion", "description": "The text-format version to use with Prometheus scraping. 0.0.4 = text\/plain; version=0.0.4; charset=utf-8 1.0.0 = application\/openmetrics-text; version=1.0.0; charset=utf-8", "sourceType": "org.apache.camel.main.MetricsConfigurationProperties", "type": "string", "javaType": "java.lang.String", "defaultValue": "0.0.4", "enum": [ "0.0.4", "1.0.0" ] }, { "name": "camel.opentelemetry.enabled", "description": "To enable OpenTelemetry", "sourceType": "org.apache.camel.main.OtelConfigurationProperties", "type": "boolean", "javaType": "boolean", "defaultValue": "false" }, { "name": "camel.opentelemetry.encoding", "description": "Sets whether the header keys need to be encoded (connector specific) or not. The value is a boolean. Dashes need for instances to be encoded for JMS property keys.", "sourceType": "org.apache.camel.main.OtelConfigurationProperties", "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 3274ceb9c0409..7f70eafc24676 100644 --- a/core/camel-main/src/main/docs/main.adoc +++ b/core/camel-main/src/main/docs/main.adoc @@ -386,7 +386,7 @@ The camel.opentelemetry supports 4 options, which are listed below. === Camel Micrometer Metrics configurations -The camel.metrics supports 9 options, which are listed below. +The camel.metrics supports 10 options, which are listed below. [width="100%",cols="2,5,^1,2",options="header"] |=== @@ -399,6 +399,7 @@ The camel.metrics supports 9 options, which are listed below. | *camel.metrics.enableRouteEvent{zwsp}Notifier* | Set whether to enable the MicrometerRouteEventNotifier for capturing metrics on the total number of routes and total number of routes running. | true | boolean | *camel.metrics.enableRoute{zwsp}Policy* | Set whether to enable the MicrometerRoutePolicyFactory for capturing metrics on route processing times. | true | boolean | *camel.metrics.namingStrategy* | Controls the name style to use for metrics. Default = uses micrometer naming convention. Legacy = uses the classic naming style (camelCase) | default | String +| *camel.metrics.routePolicyLevel* | Sets the level of information to capture. all = both context and routes. | all | String | *camel.metrics.textFormat{zwsp}Version* | The text-format version to use with Prometheus scraping. 0.0.4 = text/plain; version=0.0.4; charset=utf-8 1.0.0 = application/openmetrics-text; version=1.0.0; charset=utf-8 | 0.0.4 | String |=== diff --git a/core/camel-main/src/main/java/org/apache/camel/main/MetricsConfigurationProperties.java b/core/camel-main/src/main/java/org/apache/camel/main/MetricsConfigurationProperties.java index 108c9dfc2a82b..772d3242c17cd 100644 --- a/core/camel-main/src/main/java/org/apache/camel/main/MetricsConfigurationProperties.java +++ b/core/camel-main/src/main/java/org/apache/camel/main/MetricsConfigurationProperties.java @@ -33,6 +33,8 @@ public class MetricsConfigurationProperties implements BootstrapCloseable { private String namingStrategy; @Metadata(defaultValue = "true") private boolean enableRoutePolicy = true; + @Metadata(defaultValue = "all", enums = "all,route,context") + private String routePolicyLevel = "all"; private boolean enableMessageHistory; @Metadata(defaultValue = "true") private boolean enableExchangeEventNotifier = true; @@ -88,6 +90,17 @@ public void setEnableRoutePolicy(boolean enableRoutePolicy) { this.enableRoutePolicy = enableRoutePolicy; } + public String getRoutePolicyLevel() { + return routePolicyLevel; + } + + /** + * Sets the level of information to capture. all = both context and routes. + */ + public void setRoutePolicyLevel(String routePolicyLevel) { + this.routePolicyLevel = routePolicyLevel; + } + public boolean isEnableMessageHistory() { return enableMessageHistory; } @@ -180,6 +193,14 @@ public MetricsConfigurationProperties withEnableRoutePolicy(boolean enableRouteP return this; } + /** + * Sets the level of information to capture. all = both context and routes. + */ + public MetricsConfigurationProperties withRoutePolicyLevel(String routePolicyLevel) { + this.routePolicyLevel = routePolicyLevel; + return this; + } + /** * To enable Micrometer metrics. */ 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 9229bcda79721..f783da381745d 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 @@ -151,6 +151,22 @@ 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. +Added context level metrics to `camel-micrometer`. The metrics with key `camel.route.policy` now include +tag `eventType` that specifies if the metrics is for a route or the entire camel context. +You can turn off context level metrics, by setting `contenxtEnabled=false` on the factory such as: + +[source,java] +---- +factory.getPolicyConfiguration().setContextEnabled(false); +---- + +This can also be done easily from `application.properties` such as: + +[source,properties] +---- +camel.metrics.routePolicyLevel=route +---- + === camel-openapi-java and camel-rest-openapi Dropped support for the old Swagger 2.0 spec. Only OpenAPI v3 specs is supported now. diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/ListMetric.java b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/ListMetric.java index 289c93a2dcbd3..c92d63dd7146d 100644 --- a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/ListMetric.java +++ b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/ListMetric.java @@ -46,7 +46,7 @@ public class ListMetric extends ProcessWatchCommand { String sort; @CommandLine.Option(names = { "--filter" }, - description = "Filter metric by type or name") + description = "Filter metric by type, name or tags") String filter; @CommandLine.Option(names = { "--tags" }, @@ -136,7 +136,8 @@ public Integer doProcessWatchCall() throws Exception { if (!all && getNumber(row.count).isEmpty()) { continue; } - if (filter == null || row.type.equals(filter) || row.metricName.contains(filter)) { + if (filter == null || row.type.equals(filter) || row.metricName.contains(filter) + || row.tags.contains(filter)) { rows.add(row); } }