[io.metrics] Fix MetricsService breaking REST API #10640 (#10644)

* [io.metrics] Fix MetricsService breaking REST API #10640

Signed-off-by: Robert Bach <openhab@mortalsilence.net>
This commit is contained in:
pravussum 2021-05-04 21:24:01 +02:00 committed by GitHub
parent 9441cfffe8
commit 582ef280e5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 47 additions and 122 deletions

View File

@ -46,7 +46,7 @@ For a start, the following formats are supported:
### Prometheus
Once the IO addon is installed, the Prometheus endpoint will be available under:
_<openhab_host>:8080/metrics/prometheus_
_<openhab_host>:8080/rest/metrics/prometheus_
Refer to the [Prometheus](https://prometheus.io/) documentation on how to setup a Prometheus instance and add a scrape configuration. A typical scrape config could look like this (excerpt from `/etc/prometheus/prometheus.yml`):
@ -55,7 +55,7 @@ scrape_configs:
- job_name: 'openhab'
scrape_interval: 1m
scheme: http
metrics_path: /metrics/prometheus
metrics_path: /rest/metrics/prometheus
static_configs:
- targets:
- 'openhab.local:8080'

View File

@ -74,5 +74,11 @@
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.openhab.core.bundles</groupId>
<artifactId>org.openhab.core.io.rest</artifactId>
<version>${project.version}</version>
<scope>provided</scope>
</dependency>
</dependencies>
</project>

View File

@ -12,7 +12,10 @@
*/
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;
import javax.ws.rs.GET;
@ -23,8 +26,14 @@ import javax.ws.rs.core.MediaType;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.core.auth.Role;
import org.openhab.core.config.core.ConfigurableService;
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.osgi.service.component.annotations.Activate;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Modified;
import org.osgi.service.component.annotations.Reference;
import org.osgi.service.jaxrs.whiteboard.JaxrsWhiteboardConstants;
import org.osgi.service.jaxrs.whiteboard.propertytypes.JSONRequired;
@ -43,24 +52,27 @@ import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.tags.Tag;
/**
* * The {@link MetricsRestController} class implements the REST endpoints for all pull based monitoring systems.
* The {@link MetricsRestController} class implements the REST endpoints for all pull based monitoring systems.
*
* @author Robert Bach - Initial contribution
*/
@Component(immediate = true, service = MetricsRestController.class)
@JaxrsResource
@JaxrsApplicationSelect("(" + JaxrsWhiteboardConstants.JAX_RS_NAME + "=" + MetricsService.METRICS_APP_NAME + ")")
@Path("")
@JaxrsApplicationSelect("(" + JaxrsWhiteboardConstants.JAX_RS_NAME + "=" + RESTConstants.JAX_RS_NAME + ")")
@Path(MetricsRestController.PATH_METRICS)
@JSONRequired
@RolesAllowed({ Role.USER, Role.ADMIN })
@Tag(name = MetricsRestController.PATH_METRICS)
@NonNullByDefault
@ConfigurableService(category = "io", label = "Metrics service", description_uri = "io:metrics")
public class MetricsRestController {
private final Logger logger = LoggerFactory.getLogger(MetricsRestController.class);
public static final String PATH_METRICS = "metrics";
private @Nullable CompositeMeterRegistry meterRegistry = null;
private final PrometheusMeterRegistry prometheusMeterRegistry = new PrometheusMeterRegistry(
PrometheusConfig.DEFAULT);
private final Set<MetricsExporter> metricsExporters = new HashSet<>();
private @Nullable MetricsConfiguration config;
@GET
@Path("/prometheus")
@ -79,5 +91,29 @@ public class MetricsRestController {
meterRegistry = meterRegistryProvider.getOHMeterRegistry();
Objects.requireNonNull(meterRegistry).add(prometheusMeterRegistry);
logger.debug("Core metrics registry retrieved and Prometheus registry added successfully.");
updateMeterRegistry();
}
@Activate
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());
updateConfig(configuration);
updateMeterRegistry();
}
@Modified
protected synchronized void modified(Map<@Nullable String, @Nullable Object> configuration) {
updateConfig(configuration);
}
private void updateConfig(@Nullable Map<@Nullable String, @Nullable Object> configuration) {
this.config = new Configuration(configuration).as(MetricsConfiguration.class);
logger.debug("Configuration: {}", this.config);
this.metricsExporters.forEach(e -> e.updateExporterState(config));
}
private void updateMeterRegistry() {
this.metricsExporters.forEach(e -> e.setMeterRegistry(meterRegistry));
}
}

View File

@ -1,117 +0,0 @@
/**
* 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;
import java.util.Dictionary;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import javax.ws.rs.core.Application;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.core.config.core.ConfigurableService;
import org.openhab.core.config.core.Configuration;
import org.openhab.core.io.monitor.MeterRegistryProvider;
import org.openhab.io.metrics.exporters.InfluxMetricsExporter;
import org.osgi.framework.BundleContext;
import org.osgi.framework.FrameworkUtil;
import org.osgi.framework.ServiceRegistration;
import org.osgi.service.component.annotations.Activate;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Deactivate;
import org.osgi.service.component.annotations.Modified;
import org.osgi.service.component.annotations.Reference;
import org.osgi.service.jaxrs.whiteboard.JaxrsWhiteboardConstants;
import org.osgi.service.jaxrs.whiteboard.propertytypes.JaxrsName;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import io.micrometer.core.instrument.composite.CompositeMeterRegistry;
/**
* The {@link MetricsService} class implements the central component controlling the different metric endpoints/syncers.
*
* @author Robert Bach - Initial contribution
*/
@NonNullByDefault
@Component(immediate = true, service = MetricsService.class)
@ConfigurableService(category = "io", label = "Metrics service", description_uri = "io:metrics")
public class MetricsService {
public static final String METRICS_APP_NAME = "Metrics";
public static final String ROOT = "/metrics";
private final Logger logger = LoggerFactory.getLogger(MetricsService.class);
private @Nullable ServiceRegistration<Application> restService = null;
private @Nullable MetricsConfiguration config;
@Reference
protected @NonNullByDefault({}) MetricsRestController metrics;
private Set<MetricsExporter> metricsExporters = new HashSet<>();
private @Nullable CompositeMeterRegistry meterRegistry = null;
@Activate
protected void activate(Map<@Nullable String, @Nullable Object> configuration) {
MetricsRestApplication app = new MetricsRestApplication();
BundleContext context = FrameworkUtil.getBundle(getClass()).getBundleContext();
restService = context.registerService(Application.class, app, getServiceProperties());
logger.info("Metrics service available under {}.", ROOT);
metricsExporters.add(new InfluxMetricsExporter());
updateConfig(configuration);
updateMeterRegistry();
}
@Modified
protected synchronized void modified(Map<@Nullable String, @Nullable Object> configuration) {
updateConfig(configuration);
}
@Deactivate
protected void deactivate() {
if (restService != null) {
Objects.requireNonNull(restService).unregister();
}
}
Dictionary<@Nullable String, @Nullable String> getServiceProperties() {
Dictionary<@Nullable String, @Nullable String> dict = new Hashtable<>();
dict.put(JaxrsWhiteboardConstants.JAX_RS_APPLICATION_BASE, ROOT);
return dict;
}
@JaxrsName(METRICS_APP_NAME)
private class MetricsRestApplication extends Application {
@NonNullByDefault({})
@Override
public Set<Object> getSingletons() {
return Set.of(metrics);
}
}
@Reference
public void setMeterRegistryProvider(MeterRegistryProvider meterRegistryProvider) {
meterRegistry = meterRegistryProvider.getOHMeterRegistry();
updateMeterRegistry();
}
private void updateConfig(@Nullable Map<@Nullable String, @Nullable Object> configuration) {
this.config = new Configuration(configuration).as(MetricsConfiguration.class);
logger.debug("Configuration: {}", this.config);
this.metricsExporters.forEach(e -> e.updateExporterState(config));
}
private void updateMeterRegistry() {
this.metricsExporters.forEach(e -> e.setMeterRegistry(meterRegistry));
}
}