You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by da...@apache.org on 2023/11/16 14:50:50 UTC
(camel) 14/16: CAMEL-20105: camel-micromemter - Make it easier to configure for camel-main
This is an automated email from the ASF dual-hosted git repository.
davsclaus pushed a commit to branch mm
in repository https://gitbox.apache.org/repos/asf/camel.git
commit 222300e9087af3b833d539774c67c443bbef288d
Author: Claus Ibsen <cl...@gmail.com>
AuthorDate: Thu Nov 16 15:05:13 2023 +0100
CAMEL-20105: camel-micromemter - Make it easier to configure for camel-main
---
components/camel-micrometer-prometheus/pom.xml | 44 +++++++++
.../micrometer/prometheus/JandexHelper.java | 44 +++++++++
.../prometheus/MicrometerPrometheusConfigurer.java | 6 ++
.../prometheus/MicrometerPrometheus.java | 102 ++++++++++++++++++++-
.../MetricsConfigurationPropertiesConfigurer.java | 6 ++
.../camel-main-configuration-metadata.json | 1 +
core/camel-main/src/main/docs/main.adoc | 3 +-
.../camel/main/MetricsConfigurationProperties.java | 22 +++++
8 files changed, 222 insertions(+), 6 deletions(-)
diff --git a/components/camel-micrometer-prometheus/pom.xml b/components/camel-micrometer-prometheus/pom.xml
index 72cb76f0fa3..d6e883369ec 100644
--- a/components/camel-micrometer-prometheus/pom.xml
+++ b/components/camel-micrometer-prometheus/pom.xml
@@ -46,10 +46,20 @@
<artifactId>camel-platform-http-main</artifactId>
</dependency>
+ <dependency>
+ <groupId>io.micrometer</groupId>
+ <artifactId>micrometer-core</artifactId>
+ </dependency>
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-registry-prometheus</artifactId>
</dependency>
+ <!-- to load micrometer binders -->
+ <dependency>
+ <groupId>io.smallrye</groupId>
+ <artifactId>jandex</artifactId>
+ <version>${jandex-version}</version>
+ </dependency>
<!-- testing -->
<dependency>
@@ -100,4 +110,38 @@
</dependencies>
+ <build>
+ <plugins>
+
+ <!-- generate jandex index for all the micrometer binders that can be enabled -->
+ <plugin>
+ <groupId>io.smallrye</groupId>
+ <artifactId>jandex-maven-plugin</artifactId>
+ <version>${jandex-version}</version>
+ <executions>
+ <execution>
+ <id>make-index</id>
+ <goals>
+ <goal>jandex</goal>
+ </goals>
+ <configuration>
+ <indexName>micrometer-binder-index.dat</indexName>
+ <fileSets>
+ <fileSet>
+ <dependency>
+ <groupId>io.micrometer</groupId>
+ <artifactId>micrometer-core</artifactId>
+ </dependency>
+ <includes>
+ <include>io/micrometer/core/instrument/binder/**/*.class</include>
+ </includes>
+ </fileSet>
+ </fileSets>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+
</project>
diff --git a/components/camel-micrometer-prometheus/src/generated/java/org/apache/camel/component/micrometer/prometheus/JandexHelper.java b/components/camel-micrometer-prometheus/src/generated/java/org/apache/camel/component/micrometer/prometheus/JandexHelper.java
new file mode 100644
index 00000000000..93d05bbe4a4
--- /dev/null
+++ b/components/camel-micrometer-prometheus/src/generated/java/org/apache/camel/component/micrometer/prometheus/JandexHelper.java
@@ -0,0 +1,44 @@
+/*
+ * 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.prometheus;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.util.IOHelper;
+import org.jboss.jandex.Index;
+import org.jboss.jandex.IndexReader;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+public final class JandexHelper {
+
+ private JandexHelper() {
+ }
+
+ public static Index readJandexIndex(CamelContext camelContext) throws IOException {
+ InputStream is = camelContext.getClassResolver().loadResourceAsStream("META-INF/micrometer-binder-index.dat");
+ try {
+ if (is != null) {
+ IndexReader reader = new IndexReader(is);
+ return reader.read();
+ }
+ } finally {
+ IOHelper.close(is);
+ }
+ return null;
+ }
+}
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 abad014040c..b18ea39de08 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
@@ -21,6 +21,8 @@ public class MicrometerPrometheusConfigurer extends org.apache.camel.support.com
public boolean configure(CamelContext camelContext, Object obj, String name, Object value, boolean ignoreCase) {
org.apache.camel.component.micrometer.prometheus.MicrometerPrometheus target = (org.apache.camel.component.micrometer.prometheus.MicrometerPrometheus) obj;
switch (ignoreCase ? name.toLowerCase() : name) {
+ case "binders":
+ case "Binders": target.setBinders(property(camelContext, java.lang.String.class, value)); return true;
case "camelcontext":
case "CamelContext": target.setCamelContext(property(camelContext, org.apache.camel.CamelContext.class, value)); return true;
case "enableexchangeeventnotifier":
@@ -40,6 +42,8 @@ public class MicrometerPrometheusConfigurer extends org.apache.camel.support.com
@Override
public Class<?> getOptionType(String name, boolean ignoreCase) {
switch (ignoreCase ? name.toLowerCase() : name) {
+ case "binders":
+ case "Binders": return java.lang.String.class;
case "camelcontext":
case "CamelContext": return org.apache.camel.CamelContext.class;
case "enableexchangeeventnotifier":
@@ -60,6 +64,8 @@ public class MicrometerPrometheusConfigurer extends org.apache.camel.support.com
public Object getOptionValue(Object obj, String name, boolean ignoreCase) {
org.apache.camel.component.micrometer.prometheus.MicrometerPrometheus target = (org.apache.camel.component.micrometer.prometheus.MicrometerPrometheus) obj;
switch (ignoreCase ? name.toLowerCase() : name) {
+ case "binders":
+ case "Binders": return target.getBinders();
case "camelcontext":
case "CamelContext": return target.getCamelContext();
case "enableexchangeeventnotifier":
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 1f20b3e3841..cb04572ad60 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
@@ -16,6 +16,15 @@
*/
package org.apache.camel.component.micrometer.prometheus;
+import java.io.Closeable;
+import java.io.IOException;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Optional;
+import java.util.Set;
+import java.util.StringJoiner;
+
+import io.micrometer.core.instrument.binder.MeterBinder;
import io.micrometer.prometheus.PrometheusConfig;
import io.micrometer.prometheus.PrometheusMeterRegistry;
import io.prometheus.client.exporter.common.TextFormat;
@@ -40,6 +49,11 @@ import org.apache.camel.spi.ManagementStrategy;
import org.apache.camel.spi.Metadata;
import org.apache.camel.spi.annotations.JdkService;
import org.apache.camel.support.service.ServiceSupport;
+import org.apache.camel.util.IOHelper;
+import org.apache.camel.util.StringHelper;
+import org.jboss.jandex.ClassInfo;
+import org.jboss.jandex.DotName;
+import org.jboss.jandex.Index;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -50,17 +64,18 @@ public class MicrometerPrometheus extends ServiceSupport implements CamelMetrics
private static final Logger LOG = LoggerFactory.getLogger(MicrometerPrometheus.class);
+ private static final String JANDEX_INDEX = "META-INF/micrometer-binder-index.dat";
+
private MainHttpServer server;
private VertxPlatformHttpRouter router;
private PlatformHttpComponent platformHttpComponent;
- // TODO: option include JVM metrics
- // TODO: option include platform-http metrics
// TODO: include easily with jbang
// TODO: docs
private CamelContext camelContext;
private final PrometheusMeterRegistry meterRegistry = new PrometheusMeterRegistry(PrometheusConfig.DEFAULT);
+ private final Set<MeterBinder> createdBinders = new HashSet<>();
@Metadata(defaultValue = "true")
private boolean enableRoutePolicy = true;
@@ -72,6 +87,8 @@ public class MicrometerPrometheus extends ServiceSupport implements CamelMetrics
private boolean enableRouteEventNotifier = true;
@Metadata(defaultValue = "0.0.4", enums = "0.0.4,1.0.0")
private String textFormatVersion = "0.0.4";
+ @Metadata
+ private String binders;
@Override
public CamelContext getCamelContext() {
@@ -139,17 +156,34 @@ public class MicrometerPrometheus extends ServiceSupport implements CamelMetrics
/**
* 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 = text/plain; version=0.0.4; charset=utf-8 1.0.0 = application/openmetrics-text; version=1.0.0;
+ * charset=utf-8
*/
public void setTextFormatVersion(String textFormatVersion) {
this.textFormatVersion = textFormatVersion;
}
+ public String getBinders() {
+ return binders;
+ }
+
+ /**
+ * Additional Micrometer binders to include such as jvm-memory, processor, jvm-thread, and so forth. Multiple
+ * binders can be separated by comma.
+ */
+ public void setBinders(String binders) {
+ this.binders = binders;
+ }
+
@Override
protected void doStart() throws Exception {
super.doStart();
+ if (binders != null) {
+ // load binders from micrometer
+ initBinders();
+ }
+
if (isEnableRoutePolicy()) {
MicrometerRoutePolicyFactory factory = new MicrometerRoutePolicyFactory();
factory.setMeterRegistry(meterRegistry);
@@ -190,11 +224,69 @@ public class MicrometerPrometheus extends ServiceSupport implements CamelMetrics
}
}
+ private void initBinders() throws IOException {
+ LOG.debug("Loading {}", JANDEX_INDEX);
+ Index index = JandexHelper.readJandexIndex(camelContext);
+ if (index == null) {
+ LOG.warn("Cannot read {} with list of known MeterBinder classes}", JANDEX_INDEX);
+ } else {
+ DotName dn = DotName.createSimple(MeterBinder.class);
+ List<ClassInfo> classes = index.getKnownDirectImplementors(dn);
+ LOG.debug("Found {} MeterBinder classes from {}", classes.size(), JANDEX_INDEX);
+
+ StringJoiner sj = new StringJoiner(", ");
+ for (String binder : binders.split(",")) {
+ binder = binder.trim();
+ binder = StringHelper.dashToCamelCase(binder);
+ binder = binder.toLowerCase();
+
+ final String target = binder;
+ Optional<ClassInfo> found = classes.stream()
+ // use naming convention with and without metrics
+ .filter(c -> c.name().local().toLowerCase().equals(target)
+ || c.name().local().toLowerCase().equals(target + "metrics"))
+ .findFirst();
+
+ if (found.isPresent()) {
+ String fqn = found.get().name().toString();
+ LOG.debug("Creating MeterBinder: {}", fqn);
+ try {
+ Class<MeterBinder> clazz = camelContext.getClassResolver().resolveClass(fqn, MeterBinder.class);
+ MeterBinder mb = camelContext.getInjector().newInstance(clazz);
+ if (mb != null) {
+ mb.bindTo(meterRegistry);
+ createdBinders.add(mb);
+ sj.add(mb.getClass().getSimpleName());
+ }
+ } catch (Exception e) {
+ LOG.warn("Error creating MeterBinder: {} due to: {}", fqn, e.getMessage(), e);
+ }
+ }
+ }
+ if (!createdBinders.isEmpty()) {
+ LOG.info("Registered {} MeterBinders: {}", createdBinders.size(), sj);
+ }
+ }
+ }
+
+ @Override
+ protected void doShutdown() throws Exception {
+ super.doShutdown();
+
+ for (MeterBinder mb : createdBinders) {
+ if (mb instanceof Closeable ac) {
+ IOHelper.close(ac);
+ }
+ }
+ createdBinders.clear();
+ }
+
protected void setupHttpScraper() {
Route metrics = router.route("/q/metrics");
metrics.method(HttpMethod.GET);
- final String format = "0.0.4".equals(textFormatVersion) ? TextFormat.CONTENT_TYPE_004 : TextFormat.CONTENT_TYPE_OPENMETRICS_100;
+ final String format
+ = "0.0.4".equals(textFormatVersion) ? TextFormat.CONTENT_TYPE_004 : TextFormat.CONTENT_TYPE_OPENMETRICS_100;
metrics.produces(format);
Handler<RoutingContext> handler = new Handler<RoutingContext>() {
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 ed323ad35fd..5ff6c35f698 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
@@ -21,6 +21,8 @@ public class MetricsConfigurationPropertiesConfigurer extends org.apache.camel.s
public boolean configure(CamelContext camelContext, Object obj, String name, Object value, boolean ignoreCase) {
org.apache.camel.main.MetricsConfigurationProperties target = (org.apache.camel.main.MetricsConfigurationProperties) obj;
switch (ignoreCase ? name.toLowerCase() : name) {
+ case "binders":
+ case "Binders": target.setBinders(property(camelContext, java.lang.String.class, value)); return true;
case "enableexchangeeventnotifier":
case "EnableExchangeEventNotifier": target.setEnableExchangeEventNotifier(property(camelContext, boolean.class, value)); return true;
case "enablemessagehistory":
@@ -40,6 +42,8 @@ public class MetricsConfigurationPropertiesConfigurer extends org.apache.camel.s
@Override
public Class<?> getOptionType(String name, boolean ignoreCase) {
switch (ignoreCase ? name.toLowerCase() : name) {
+ case "binders":
+ case "Binders": return java.lang.String.class;
case "enableexchangeeventnotifier":
case "EnableExchangeEventNotifier": return boolean.class;
case "enablemessagehistory":
@@ -60,6 +64,8 @@ public class MetricsConfigurationPropertiesConfigurer extends org.apache.camel.s
public Object getOptionValue(Object obj, String name, boolean ignoreCase) {
org.apache.camel.main.MetricsConfigurationProperties target = (org.apache.camel.main.MetricsConfigurationProperties) obj;
switch (ignoreCase ? name.toLowerCase() : name) {
+ case "binders":
+ case "Binders": return target.getBinders();
case "enableexchangeeventnotifier":
case "EnableExchangeEventNotifier": return target.isEnableExchangeEventNotifier();
case "enablemessagehistory":
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 22167f65ed6..b394013bf78 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
@@ -180,6 +180,7 @@
{ "name": "camel.lra.enabled", "description": "To enable Saga LRA", "sourceType": "org.apache.camel.main.LraConfigurationProperties", "type": "boolean", "javaType": "boolean", "defaultValue": false },
{ "name": "camel.lra.localParticipantContextPath", "description": "The context-path for the local participant. Is default \/lra-participant", "sourceType": "org.apache.camel.main.LraConfigurationProperties", "type": "string", "javaType": "java.lang.String", "defaultValue": "\/lra-participant" },
{ "name": "camel.lra.localParticipantUrl", "description": "The URL for the local participant", "sourceType": "org.apache.camel.main.LraConfigurationProperties", "type": "string", "javaType": "java.lang.String" },
+ { "name": "camel.metrics.binders", "description": "Additional Micrometer binders to include such as jvm-memory, processor, jvm-thread, and so forth. Multiple binders can be separated by comma.", "sourceType": "org.apache.camel.main.MetricsConfigurationProperties", "type": "string", "javaType": "java.lang.String" },
{ "name": "camel.metrics.enabled", "description": "To enable Micrometer metrics.", "sourceType": "org.apache.camel.main.MetricsConfigurationProperties", "type": "boolean", "javaType": "boolean", "defaultValue": "false" },
{ "name": "camel.metrics.enableExchangeEventNotifier", "description": "Set whether to enable the MicrometerExchangeEventNotifier for capturing metrics on exchange processing times.", "sourceType": "org.apache.camel.main.MetricsConfigurationProperties", "type": "boolean", "javaType": "boolean", "defaultValue": true },
{ "name": "camel.metrics.enableMessageHistory", "description": "Set whether to enable the MicrometerMessageHistoryFactory for capturing metrics on individual route node processing times. Depending on the number of configured route nodes, there is the potential to create a large volume of metrics. Therefore, this option is disabled by default.", "sourceType": "org.apache.camel.main.MetricsConfigurationProperties", "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 426dff178b1..14021ec8ebf 100644
--- a/core/camel-main/src/main/docs/main.adoc
+++ b/core/camel-main/src/main/docs/main.adoc
@@ -347,11 +347,12 @@ The camel.opentelemetry supports 4 options, which are listed below.
=== Camel Micrometer Metrics configurations
-The camel.metrics supports 6 options, which are listed below.
+The camel.metrics supports 7 options, which are listed below.
[width="100%",cols="2,5,^1,2",options="header"]
|===
| Name | Description | Default | Type
+| *camel.metrics.binders* | Additional Micrometer binders to include such as jvm-memory, processor, jvm-thread, and so forth. Multiple binders can be separated by comma. | | String
| *camel.metrics.enabled* | To enable Micrometer metrics. | false | boolean
| *camel.metrics.enableExchange{zwsp}EventNotifier* | Set whether to enable the MicrometerExchangeEventNotifier for capturing metrics on exchange processing times. | true | boolean
| *camel.metrics.enableMessage{zwsp}History* | Set whether to enable the MicrometerMessageHistoryFactory for capturing metrics on individual route node processing times. Depending on the number of configured route nodes, there is the potential to create a large volume of metrics. Therefore, this option is disabled by default. | false | boolean
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 dd55c2951c3..badc1b27506 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
@@ -38,6 +38,8 @@ public class MetricsConfigurationProperties implements BootstrapCloseable {
private boolean enableRouteEventNotifier = true;
@Metadata(defaultValue = "0.0.4", enums = "0.0.4,1.0.0")
private String textFormatVersion = "0.0.4";
+ @Metadata
+ private String binders;
public MetricsConfigurationProperties(MainConfigurationProperties parent) {
this.parent = parent;
@@ -121,6 +123,18 @@ public class MetricsConfigurationProperties implements BootstrapCloseable {
this.textFormatVersion = textFormatVersion;
}
+ public String getBinders() {
+ return binders;
+ }
+
+ /**
+ * Additional Micrometer binders to include such as jvm-memory, processor, jvm-thread, and so forth. Multiple
+ * binders can be separated by comma.
+ */
+ public void setBinders(String binders) {
+ this.binders = binders;
+ }
+
@Override
public void close() {
parent = null;
@@ -182,5 +196,13 @@ public class MetricsConfigurationProperties implements BootstrapCloseable {
return this;
}
+ /**
+ * Additional Micrometer binders to include such as jvm-memory, processor, jvm-thread, and so forth. Multiple
+ * binders can be separated by comma.
+ */
+ public MetricsConfigurationProperties withbinders(String binders) {
+ this.binders = binders;
+ return this;
+ }
}