* [io.metrics] Fix MetricsService breaking REST API #10640 Signed-off-by: Robert Bach <openhab@mortalsilence.net>
This commit is contained in:
parent
9441cfffe8
commit
582ef280e5
|
@ -46,7 +46,7 @@ For a start, the following formats are supported:
|
||||||
### Prometheus
|
### Prometheus
|
||||||
|
|
||||||
Once the IO addon is installed, the Prometheus endpoint will be available under:
|
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`):
|
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'
|
- job_name: 'openhab'
|
||||||
scrape_interval: 1m
|
scrape_interval: 1m
|
||||||
scheme: http
|
scheme: http
|
||||||
metrics_path: /metrics/prometheus
|
metrics_path: /rest/metrics/prometheus
|
||||||
static_configs:
|
static_configs:
|
||||||
- targets:
|
- targets:
|
||||||
- 'openhab.local:8080'
|
- 'openhab.local:8080'
|
||||||
|
|
|
@ -74,5 +74,11 @@
|
||||||
</exclusion>
|
</exclusion>
|
||||||
</exclusions>
|
</exclusions>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.openhab.core.bundles</groupId>
|
||||||
|
<artifactId>org.openhab.core.io.rest</artifactId>
|
||||||
|
<version>${project.version}</version>
|
||||||
|
<scope>provided</scope>
|
||||||
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
</project>
|
</project>
|
||||||
|
|
|
@ -12,7 +12,10 @@
|
||||||
*/
|
*/
|
||||||
package org.openhab.io.metrics;
|
package org.openhab.io.metrics;
|
||||||
|
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
import javax.annotation.security.RolesAllowed;
|
import javax.annotation.security.RolesAllowed;
|
||||||
import javax.ws.rs.GET;
|
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.NonNullByDefault;
|
||||||
import org.eclipse.jdt.annotation.Nullable;
|
import org.eclipse.jdt.annotation.Nullable;
|
||||||
import org.openhab.core.auth.Role;
|
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.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.Component;
|
||||||
|
import org.osgi.service.component.annotations.Modified;
|
||||||
import org.osgi.service.component.annotations.Reference;
|
import org.osgi.service.component.annotations.Reference;
|
||||||
import org.osgi.service.jaxrs.whiteboard.JaxrsWhiteboardConstants;
|
import org.osgi.service.jaxrs.whiteboard.JaxrsWhiteboardConstants;
|
||||||
import org.osgi.service.jaxrs.whiteboard.propertytypes.JSONRequired;
|
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;
|
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
|
* @author Robert Bach - Initial contribution
|
||||||
*/
|
*/
|
||||||
@Component(immediate = true, service = MetricsRestController.class)
|
@Component(immediate = true, service = MetricsRestController.class)
|
||||||
@JaxrsResource
|
@JaxrsResource
|
||||||
@JaxrsApplicationSelect("(" + JaxrsWhiteboardConstants.JAX_RS_NAME + "=" + MetricsService.METRICS_APP_NAME + ")")
|
@JaxrsApplicationSelect("(" + JaxrsWhiteboardConstants.JAX_RS_NAME + "=" + RESTConstants.JAX_RS_NAME + ")")
|
||||||
@Path("")
|
@Path(MetricsRestController.PATH_METRICS)
|
||||||
@JSONRequired
|
@JSONRequired
|
||||||
@RolesAllowed({ Role.USER, Role.ADMIN })
|
@RolesAllowed({ Role.USER, Role.ADMIN })
|
||||||
@Tag(name = MetricsRestController.PATH_METRICS)
|
@Tag(name = MetricsRestController.PATH_METRICS)
|
||||||
@NonNullByDefault
|
@NonNullByDefault
|
||||||
|
@ConfigurableService(category = "io", label = "Metrics service", description_uri = "io:metrics")
|
||||||
public class MetricsRestController {
|
public class MetricsRestController {
|
||||||
private final Logger logger = LoggerFactory.getLogger(MetricsRestController.class);
|
private final Logger logger = LoggerFactory.getLogger(MetricsRestController.class);
|
||||||
public static final String PATH_METRICS = "metrics";
|
public static final String PATH_METRICS = "metrics";
|
||||||
private @Nullable CompositeMeterRegistry meterRegistry = null;
|
private @Nullable CompositeMeterRegistry meterRegistry = null;
|
||||||
private final PrometheusMeterRegistry prometheusMeterRegistry = new PrometheusMeterRegistry(
|
private final PrometheusMeterRegistry prometheusMeterRegistry = new PrometheusMeterRegistry(
|
||||||
PrometheusConfig.DEFAULT);
|
PrometheusConfig.DEFAULT);
|
||||||
|
private final Set<MetricsExporter> metricsExporters = new HashSet<>();
|
||||||
|
private @Nullable MetricsConfiguration config;
|
||||||
|
|
||||||
@GET
|
@GET
|
||||||
@Path("/prometheus")
|
@Path("/prometheus")
|
||||||
|
@ -79,5 +91,29 @@ public class MetricsRestController {
|
||||||
meterRegistry = meterRegistryProvider.getOHMeterRegistry();
|
meterRegistry = meterRegistryProvider.getOHMeterRegistry();
|
||||||
Objects.requireNonNull(meterRegistry).add(prometheusMeterRegistry);
|
Objects.requireNonNull(meterRegistry).add(prometheusMeterRegistry);
|
||||||
logger.debug("Core metrics registry retrieved and Prometheus registry added successfully.");
|
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));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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));
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in New Issue