From 30198e273ab974c0990d64e02602f44a9a8ba348 Mon Sep 17 00:00:00 2001 From: Wouter Born Date: Thu, 16 Sep 2021 09:11:12 +0200 Subject: [PATCH] [metrics] Add Java Management Extensions (JMX) metrics exporter (#11249) * Add Java Management Extensions (JMX) metrics exporter * Use groups in metrics add-on configuration * Improve null annotations * Update documentation Signed-off-by: Wouter Born --- bundles/org.openhab.io.metrics/README.md | 31 +++++--- bundles/org.openhab.io.metrics/pom.xml | 12 ++++ .../io/metrics/MetricsConfiguration.java | 8 ++- .../openhab/io/metrics/MetricsExporter.java | 4 +- .../io/metrics/MetricsRestController.java | 11 +-- .../exporters/InfluxMetricsExporter.java | 18 ++--- .../metrics/exporters/JmxMetricsExporter.java | 72 +++++++++++++++++++ .../main/resources/OH-INF/config/config.xml | 35 ++++++--- 8 files changed, 152 insertions(+), 39 deletions(-) create mode 100644 bundles/org.openhab.io.metrics/src/main/java/org/openhab/io/metrics/exporters/JmxMetricsExporter.java diff --git a/bundles/org.openhab.io.metrics/README.md b/bundles/org.openhab.io.metrics/README.md index 5060d4504..1ed329104 100644 --- a/bundles/org.openhab.io.metrics/README.md +++ b/bundles/org.openhab.io.metrics/README.md @@ -33,9 +33,10 @@ Support for push-based monitoring systems (e. g. InfluxDB) have to be enabled se The following configuration parameters can be set: -|Config param|Description|Default value| -|--|--|--| -|influxMetricsEnabled|Enable the Influx (www.influxdata.com) metrics. Further configuration of the InfluxDB instance necessary.|false| +| Config param | Description | Default value | +|----------------------|-----------------------------------------------------------------------------------------------------------|---------------| +| influxMetricsEnabled | Enable the Influx (www.influxdata.com) metrics. Further configuration of the InfluxDB instance necessary. | false | +| jmxMetricsEnabled | Enable the Java Management Extensions (JMX) metrics. | false | Refer to the corresponding monitoring system sections for monitoring system specific configuration parameters. @@ -65,7 +66,7 @@ Replace `openhab.local` by the openhab host. #### Available configuration parameters -There are no Prometheus specific configuration paramters. +There are no Prometheus specific configuration parameters. ### InfluxDB @@ -73,13 +74,21 @@ The InfluxDB exporter service will start as soon as the _influxMetricsEnabled_ c #### Available configuration parameters -|Config param|Description|Default value| -|--|--|--| -|influxURL|The URL of the InfluxDB instance. Defaults to http://localhost:8086|http://localhost:8086| -|influxDB|The name of the database to use. Defaults to "openhab".|openhab| -|influxUsername|InfluxDB user name|n/a| -|influxPassword|The InfluxDB password (no default).|n/a| -|influxUpdateIntervalInSeconds|Controls how often metrics are exported to InfluxDB (in seconds). Defaults to 300|300| +| Config param | Description | Default value | +|-------------------------------|-----------------------------------------------------------------------------------|-----------------------| +| influxURL | The URL of the InfluxDB instance. Defaults to http://localhost:8086 | http://localhost:8086 | +| influxDB | The name of the database to use. Defaults to "openhab". | openhab | +| influxUsername | InfluxDB user name | n/a | +| influxPassword | The InfluxDB password (no default). | n/a | +| influxUpdateIntervalInSeconds | Controls how often metrics are exported to InfluxDB (in seconds). Defaults to 300 | 300 | + +### JMX + +The Java Management Extensions (JMX) exporter service will start as soon as the _jmxMetricsEnabled_ configuration parameter is set to true. + +You can monitor the JMX metrics using a tool like [JConsole](https://docs.oracle.com/en/java/javase/11/management/using-jconsole.html) or [VisualVM](https://visualvm.github.io/) (after installing the VisualVM-MBeans plugin). +When the JMX exporter is enabled, the metrics will be available under the "metrics" MBean. +JConsole and VisualVM will only be able to connect using JMX when openHAB is started in debug mode (use `start_debug.sh` or `start_debug.bat`). ## Additional metric formats diff --git a/bundles/org.openhab.io.metrics/pom.xml b/bundles/org.openhab.io.metrics/pom.xml index 439c3506b..91540d606 100644 --- a/bundles/org.openhab.io.metrics/pom.xml +++ b/bundles/org.openhab.io.metrics/pom.xml @@ -44,6 +44,18 @@ + + io.dropwizard.metrics + metrics-jmx + 4.0.7 + compile + + + io.micrometer + micrometer-registry-jmx + ${micrometer.version} + compile + io.micrometer micrometer-registry-prometheus diff --git a/bundles/org.openhab.io.metrics/src/main/java/org/openhab/io/metrics/MetricsConfiguration.java b/bundles/org.openhab.io.metrics/src/main/java/org/openhab/io/metrics/MetricsConfiguration.java index 08daf1219..b40ce1d6c 100644 --- a/bundles/org.openhab.io.metrics/src/main/java/org/openhab/io/metrics/MetricsConfiguration.java +++ b/bundles/org.openhab.io.metrics/src/main/java/org/openhab/io/metrics/MetricsConfiguration.java @@ -25,15 +25,17 @@ public class MetricsConfiguration { public boolean influxMetricsEnabled = false; public String influxURL = "http://localhost:8086"; public String influxDB = "openhab"; - public @Nullable String influxPassword = null; - public @Nullable String influxUsername = null; + public @Nullable String influxPassword; + public @Nullable String influxUsername; public Integer influxUpdateIntervalInSeconds = 300; + public boolean jmxMetricsEnabled = false; + @Override public String toString() { return "MetricsConfiguration{" + "influxMetricsEnabled=" + influxMetricsEnabled + ", influxURL='" + influxURL + '\'' + ", influxDB='" + influxDB + '\'' + ", influxPassword='" + influxPassword + '\'' + ", influxUsername='" + influxUsername + '\'' + ", influxUpdateIntervalInSeconds=" - + influxUpdateIntervalInSeconds + '}'; + + influxUpdateIntervalInSeconds + ", jmxMetricsEnabled=" + jmxMetricsEnabled + '}'; } } diff --git a/bundles/org.openhab.io.metrics/src/main/java/org/openhab/io/metrics/MetricsExporter.java b/bundles/org.openhab.io.metrics/src/main/java/org/openhab/io/metrics/MetricsExporter.java index cc1c644d8..6d6acad13 100644 --- a/bundles/org.openhab.io.metrics/src/main/java/org/openhab/io/metrics/MetricsExporter.java +++ b/bundles/org.openhab.io.metrics/src/main/java/org/openhab/io/metrics/MetricsExporter.java @@ -31,8 +31,8 @@ public abstract class MetricsExporter { private final Logger logger = LoggerFactory.getLogger(MetricsExporter.class); private boolean active = false; - protected @Nullable CompositeMeterRegistry meterRegistry = null; - protected @Nullable MetricsConfiguration config = null; + protected @Nullable CompositeMeterRegistry meterRegistry; + protected @Nullable MetricsConfiguration config; protected abstract void start(CompositeMeterRegistry meterRegistry, MetricsConfiguration metricsConfiguration); diff --git a/bundles/org.openhab.io.metrics/src/main/java/org/openhab/io/metrics/MetricsRestController.java b/bundles/org.openhab.io.metrics/src/main/java/org/openhab/io/metrics/MetricsRestController.java index b13b73ca4..6d42edd5b 100644 --- a/bundles/org.openhab.io.metrics/src/main/java/org/openhab/io/metrics/MetricsRestController.java +++ b/bundles/org.openhab.io.metrics/src/main/java/org/openhab/io/metrics/MetricsRestController.java @@ -14,7 +14,6 @@ package org.openhab.io.metrics; import java.util.HashSet; import java.util.Map; -import java.util.Objects; import java.util.Set; import javax.annotation.security.RolesAllowed; @@ -31,6 +30,7 @@ import org.openhab.core.config.core.Configuration; import org.openhab.core.io.monitor.MeterRegistryProvider; import org.openhab.core.io.rest.RESTConstants; import org.openhab.io.metrics.exporters.InfluxMetricsExporter; +import org.openhab.io.metrics.exporters.JmxMetricsExporter; import org.osgi.service.component.annotations.Activate; import org.osgi.service.component.annotations.Component; import org.osgi.service.component.annotations.Modified; @@ -68,7 +68,7 @@ import io.swagger.v3.oas.annotations.tags.Tag; public class MetricsRestController { private final Logger logger = LoggerFactory.getLogger(MetricsRestController.class); public static final String PATH_METRICS = "metrics"; - private @Nullable CompositeMeterRegistry meterRegistry = null; + private @Nullable CompositeMeterRegistry meterRegistry; private final PrometheusMeterRegistry prometheusMeterRegistry = new PrometheusMeterRegistry( PrometheusConfig.DEFAULT); private final Set metricsExporters = new HashSet<>(); @@ -85,11 +85,13 @@ public class MetricsRestController { @Reference public void setMeterRegistryProvider(MeterRegistryProvider meterRegistryProvider) { + CompositeMeterRegistry meterRegistry = this.meterRegistry; if (meterRegistry != null) { - Objects.requireNonNull(meterRegistry).remove(prometheusMeterRegistry); + meterRegistry.remove(prometheusMeterRegistry); } meterRegistry = meterRegistryProvider.getOHMeterRegistry(); - Objects.requireNonNull(meterRegistry).add(prometheusMeterRegistry); + meterRegistry.add(prometheusMeterRegistry); + this.meterRegistry = meterRegistry; logger.debug("Core metrics registry retrieved and Prometheus registry added successfully."); updateMeterRegistry(); } @@ -98,6 +100,7 @@ public class MetricsRestController { protected void activate(Map<@Nullable String, @Nullable Object> configuration) { logger.info("Metrics service activated, serving the following URL(s): /rest/metrics/prometheus"); metricsExporters.add(new InfluxMetricsExporter()); + metricsExporters.add(new JmxMetricsExporter()); updateConfig(configuration); updateMeterRegistry(); } diff --git a/bundles/org.openhab.io.metrics/src/main/java/org/openhab/io/metrics/exporters/InfluxMetricsExporter.java b/bundles/org.openhab.io.metrics/src/main/java/org/openhab/io/metrics/exporters/InfluxMetricsExporter.java index 8b02eac05..24e710408 100644 --- a/bundles/org.openhab.io.metrics/src/main/java/org/openhab/io/metrics/exporters/InfluxMetricsExporter.java +++ b/bundles/org.openhab.io.metrics/src/main/java/org/openhab/io/metrics/exporters/InfluxMetricsExporter.java @@ -13,7 +13,6 @@ package org.openhab.io.metrics.exporters; import java.time.Duration; -import java.util.Objects; import org.eclipse.jdt.annotation.NonNullByDefault; import org.eclipse.jdt.annotation.Nullable; @@ -26,15 +25,15 @@ import io.micrometer.influx.InfluxConfig; import io.micrometer.influx.InfluxMeterRegistry; /** - * The {@link InfluxMetricsExporter} class implements a MetricsExporter for InfluxDB + * The {@link InfluxMetricsExporter} class implements a MetricsExporter for InfluxDB. * * @author Robert Bach - Initial contribution */ @NonNullByDefault public class InfluxMetricsExporter extends MetricsExporter { - private @Nullable InfluxMeterRegistry influxMeterRegistry = null; - private @Nullable CompositeMeterRegistry meterRegistry = null; + private @Nullable InfluxMeterRegistry influxMeterRegistry; + private @Nullable CompositeMeterRegistry meterRegistry; @Override public void start(CompositeMeterRegistry meterRegistry, MetricsConfiguration metricsConfiguration) { @@ -44,14 +43,17 @@ public class InfluxMetricsExporter extends MetricsExporter { @Override public void shutdown() { + InfluxMeterRegistry influxMeterRegistry = this.influxMeterRegistry; if (influxMeterRegistry != null) { - Objects.requireNonNull(influxMeterRegistry).stop(); + influxMeterRegistry.stop(); + this.influxMeterRegistry = null; } + + CompositeMeterRegistry meterRegistry = this.meterRegistry; if (meterRegistry != null) { - Objects.requireNonNull(meterRegistry).remove(influxMeterRegistry); - meterRegistry = null; + meterRegistry.remove(influxMeterRegistry); + this.meterRegistry = null; } - influxMeterRegistry = null; } private InfluxConfig getInfluxConfig(MetricsConfiguration metricsConfiguration) { diff --git a/bundles/org.openhab.io.metrics/src/main/java/org/openhab/io/metrics/exporters/JmxMetricsExporter.java b/bundles/org.openhab.io.metrics/src/main/java/org/openhab/io/metrics/exporters/JmxMetricsExporter.java new file mode 100644 index 000000000..8644a1946 --- /dev/null +++ b/bundles/org.openhab.io.metrics/src/main/java/org/openhab/io/metrics/exporters/JmxMetricsExporter.java @@ -0,0 +1,72 @@ +/** + * Copyright (c) 2010-2021 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.io.metrics.exporters; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.jdt.annotation.Nullable; +import org.openhab.io.metrics.MetricsConfiguration; +import org.openhab.io.metrics.MetricsExporter; + +import io.micrometer.core.instrument.Clock; +import io.micrometer.core.instrument.composite.CompositeMeterRegistry; +import io.micrometer.jmx.JmxConfig; +import io.micrometer.jmx.JmxMeterRegistry; + +/** + * The {@link JmxMetricsExporter} class implements a MetricsExporter for Java Management Extensions (JMX). + * + * @author Wouter Born - Initial contribution + */ +@NonNullByDefault +public class JmxMetricsExporter extends MetricsExporter { + + private @Nullable JmxMeterRegistry jmxMeterRegistry; + private @Nullable CompositeMeterRegistry meterRegistry; + + @Override + public void start(CompositeMeterRegistry meterRegistry, MetricsConfiguration metricsConfiguration) { + jmxMeterRegistry = new JmxMeterRegistry(getJmxConfig(), Clock.SYSTEM); + meterRegistry.add(jmxMeterRegistry); + } + + @Override + public void shutdown() { + JmxMeterRegistry jmxMeterRegistry = this.jmxMeterRegistry; + if (jmxMeterRegistry != null) { + jmxMeterRegistry.stop(); + this.jmxMeterRegistry = null; + } + + CompositeMeterRegistry meterRegistry = this.meterRegistry; + if (meterRegistry != null) { + meterRegistry.remove(jmxMeterRegistry); + this.meterRegistry = null; + } + } + + private JmxConfig getJmxConfig() { + return new JmxConfig() { + @Override + @io.micrometer.core.lang.Nullable + @Nullable + public String get(@Nullable String k) { + return null; // accept the rest of the defaults + } + }; + } + + @Override + protected boolean isEnabled(MetricsConfiguration config) { + return config.jmxMetricsEnabled; + } +} diff --git a/bundles/org.openhab.io.metrics/src/main/resources/OH-INF/config/config.xml b/bundles/org.openhab.io.metrics/src/main/resources/OH-INF/config/config.xml index dd3065770..9d32dd65d 100644 --- a/bundles/org.openhab.io.metrics/src/main/resources/OH-INF/config/config.xml +++ b/bundles/org.openhab.io.metrics/src/main/resources/OH-INF/config/config.xml @@ -5,35 +5,48 @@ xsi:schemaLocation="https://openhab.org/schemas/config-description/v1.0.0 https://openhab.org/schemas/config-description-1.0.0.xsd"> - + + + + + + + + Enable the Influx (www.influxdata.com) Metrics. Further Configuration of the InfluxDB Instance Necessary. false - - + + The URL of the InfluxDB Instance. Defaults to http://localhost:8086 http://localhost:8086 - - + + The Name of the Database to Use. Defaults to "openhab". openhab - - + + The InfluxDB User Name (No Default). - - + + The InfluxDB Password (No Default). password - - + + Controls How Often Metrics Are Exported to InfluxDB (in Seconds). Defaults to 300 300 + + + + Enable the Java Management Extensions (JMX) Metrics. + false +