mirror of
https://github.com/danieldemus/openhab-core.git
synced 2025-01-25 11:45:49 +01:00
Signed-off-by: Robert Bach <openhab@mortalsilence.net>
This commit is contained in:
parent
5a4e04cb2c
commit
f061512dd5
@ -1024,7 +1024,6 @@
|
||||
<version>0.9.12</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
|
9
bundles/org.openhab.core.io.monitor/bnd.bnd
Normal file
9
bundles/org.openhab.core.io.monitor/bnd.bnd
Normal file
@ -0,0 +1,9 @@
|
||||
Bundle-SymbolicName: ${project.artifactId}
|
||||
Import-Package: \
|
||||
org.eclipse.jdt.annotation.*;resolution:=optional,\
|
||||
org.openhab.*;version=!,\
|
||||
org.osgi.framework,\
|
||||
org.osgi.service.*,\
|
||||
org.slf4j.*,\
|
||||
com.google.gson.*;version="[2.8,3)"
|
||||
Export-Package: io.micrometer.core.*
|
@ -20,6 +20,44 @@
|
||||
<artifactId>org.openhab.core</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.openhab.core.bundles</groupId>
|
||||
<artifactId>org.openhab.core.automation</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.micrometer</groupId>
|
||||
<artifactId>micrometer-core</artifactId>
|
||||
<version>1.6.3</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-dependency-plugin</artifactId>
|
||||
<version>3.1.1</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>embed-dependencies</id>
|
||||
<goals>
|
||||
<goal>unpack-dependencies</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<includeScope>runtime</includeScope>
|
||||
<includeTypes>jar</includeTypes>
|
||||
<excludeGroupIds>org.apache.karaf.features,org.openhab.core.bundles</excludeGroupIds>
|
||||
<outputDirectory>${project.build.directory}/classes</outputDirectory>
|
||||
<overWriteReleases>true</overWriteReleases>
|
||||
<overWriteSnapshots>true</overWriteSnapshots>
|
||||
<excludeTransitive>true</excludeTransitive>
|
||||
<type>jar</type>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
|
@ -0,0 +1,28 @@
|
||||
/**
|
||||
* 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.core.io.monitor;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
|
||||
import io.micrometer.core.instrument.composite.CompositeMeterRegistry;
|
||||
|
||||
/**
|
||||
* The {@link MeterRegistryProvider} interface provides a means to retrieve the default OH meter registry instance
|
||||
*
|
||||
* @author Robert Bach - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public interface MeterRegistryProvider {
|
||||
|
||||
CompositeMeterRegistry getOHMeterRegistry();
|
||||
}
|
@ -0,0 +1,114 @@
|
||||
/**
|
||||
* 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.core.io.monitor.internal;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.core.io.monitor.MeterRegistryProvider;
|
||||
import org.openhab.core.io.monitor.internal.metrics.BundleStateMetric;
|
||||
import org.openhab.core.io.monitor.internal.metrics.EventCountMetric;
|
||||
import org.openhab.core.io.monitor.internal.metrics.JVMMetric;
|
||||
import org.openhab.core.io.monitor.internal.metrics.OpenhabCoreMeterBinder;
|
||||
import org.openhab.core.io.monitor.internal.metrics.RuleMetric;
|
||||
import org.openhab.core.io.monitor.internal.metrics.ThingStateMetric;
|
||||
import org.openhab.core.io.monitor.internal.metrics.ThreadPoolMetric;
|
||||
import org.openhab.core.service.ReadyMarker;
|
||||
import org.openhab.core.service.ReadyMarkerFilter;
|
||||
import org.openhab.core.service.ReadyService;
|
||||
import org.openhab.core.service.StartLevelService;
|
||||
import org.openhab.core.thing.ThingRegistry;
|
||||
import org.osgi.framework.BundleContext;
|
||||
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.Reference;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import io.micrometer.core.instrument.Metrics;
|
||||
import io.micrometer.core.instrument.Tag;
|
||||
import io.micrometer.core.instrument.composite.CompositeMeterRegistry;
|
||||
|
||||
/**
|
||||
* The {@link DefaultMetricsRegistration} class registers all openHAB internal metrics with the global MeterRegistry.
|
||||
*
|
||||
* @author Robert Bach - Initial contribution
|
||||
*/
|
||||
@Component(immediate = true, service = MeterRegistryProvider.class)
|
||||
@NonNullByDefault
|
||||
public class DefaultMetricsRegistration implements ReadyService.ReadyTracker, MeterRegistryProvider {
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(DefaultMetricsRegistration.class);
|
||||
public static final Tag OH_CORE_METRIC_TAG = Tag.of("openhab_core_metric", "true");
|
||||
private final BundleContext bundleContext;
|
||||
private final Set<OpenhabCoreMeterBinder> meters = new HashSet<>();
|
||||
private final CompositeMeterRegistry registry = Metrics.globalRegistry;
|
||||
private final ReadyService readyService;
|
||||
private final ThingRegistry thingRegistry;
|
||||
|
||||
@Activate
|
||||
public DefaultMetricsRegistration(BundleContext bundleContext, final @Reference ReadyService readyService,
|
||||
final @Reference ThingRegistry thingRegistry) {
|
||||
this.bundleContext = bundleContext;
|
||||
this.readyService = readyService;
|
||||
this.thingRegistry = thingRegistry;
|
||||
}
|
||||
|
||||
@Activate
|
||||
protected void activate() {
|
||||
logger.trace("Activating DefaultMetricsRegistration...");
|
||||
readyService.registerTracker(this, new ReadyMarkerFilter().withType(StartLevelService.STARTLEVEL_MARKER_TYPE)
|
||||
.withIdentifier(Integer.toString(StartLevelService.STARTLEVEL_RULES)));
|
||||
}
|
||||
|
||||
@Deactivate
|
||||
public void deactivate() {
|
||||
unregisterMeters();
|
||||
readyService.unregisterTracker(this);
|
||||
}
|
||||
|
||||
private void registerMeters() {
|
||||
logger.debug("Registering meters...");
|
||||
Set<Tag> tags = Set.of(OH_CORE_METRIC_TAG);
|
||||
meters.add(new JVMMetric(tags));
|
||||
meters.add(new ThreadPoolMetric(tags));
|
||||
meters.add(new BundleStateMetric(bundleContext, tags));
|
||||
meters.add(new ThingStateMetric(bundleContext, thingRegistry, tags));
|
||||
meters.add(new EventCountMetric(bundleContext, tags));
|
||||
meters.add(new RuleMetric(bundleContext, tags));
|
||||
meters.add(new ThreadPoolMetric(tags));
|
||||
|
||||
meters.forEach(m -> m.bindTo(registry));
|
||||
}
|
||||
|
||||
private void unregisterMeters() {
|
||||
this.meters.forEach(OpenhabCoreMeterBinder::unbind);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onReadyMarkerAdded(ReadyMarker readyMarker) {
|
||||
registerMeters();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onReadyMarkerRemoved(ReadyMarker readyMarker) {
|
||||
unregisterMeters();
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompositeMeterRegistry getOHMeterRegistry() {
|
||||
return registry;
|
||||
}
|
||||
}
|
@ -17,6 +17,8 @@ import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNull;
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.core.events.Event;
|
||||
import org.openhab.core.events.EventFilter;
|
||||
import org.openhab.core.events.EventSubscriber;
|
||||
@ -37,6 +39,7 @@ import org.slf4j.LoggerFactory;
|
||||
* @author Kai Kreuzer - Initial contribution
|
||||
*/
|
||||
@Component
|
||||
@NonNullByDefault
|
||||
public class EventLogger implements EventSubscriber, ReadyTracker {
|
||||
|
||||
private final Map<String, Logger> eventLoggers = new HashMap<>();
|
||||
@ -63,6 +66,7 @@ public class EventLogger implements EventSubscriber, ReadyTracker {
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public EventFilter getEventFilter() {
|
||||
return null;
|
||||
}
|
||||
|
@ -0,0 +1,98 @@
|
||||
/**
|
||||
* 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.core.io.monitor.internal.metrics;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.osgi.framework.BundleContext;
|
||||
import org.osgi.framework.BundleEvent;
|
||||
import org.osgi.framework.BundleListener;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import io.micrometer.core.instrument.Gauge;
|
||||
import io.micrometer.core.instrument.Meter;
|
||||
import io.micrometer.core.instrument.MeterRegistry;
|
||||
import io.micrometer.core.instrument.Tag;
|
||||
import io.micrometer.core.instrument.Tags;
|
||||
|
||||
/**
|
||||
* The {@link BundleStateMetric} class implements a set of gauge metrics for the OSGI bundles states
|
||||
*
|
||||
* @author Robert Bach - Initial contribution
|
||||
*/
|
||||
public class BundleStateMetric implements OpenhabCoreMeterBinder, BundleListener {
|
||||
private final Logger logger = LoggerFactory.getLogger(BundleStateMetric.class);
|
||||
public static final String METRIC_NAME = "openhab.bundle.state";
|
||||
private static final String BUNDLE_TAG_NAME = "bundle";
|
||||
private final Meter.Id commonMeterId;
|
||||
private final Map<Meter.Id, AtomicInteger> registeredMeters = new HashMap<>();
|
||||
@Nullable
|
||||
private MeterRegistry meterRegistry = null;
|
||||
private final BundleContext bundleContext;
|
||||
|
||||
public BundleStateMetric(BundleContext bundleContext, Collection<Tag> tags) {
|
||||
commonMeterId = new Meter.Id(METRIC_NAME, Tags.of(tags), "state", "openHAB OSGi bundles state",
|
||||
Meter.Type.GAUGE);
|
||||
this.bundleContext = bundleContext;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void bindTo(@io.micrometer.core.lang.NonNull MeterRegistry meterRegistry) {
|
||||
unbind();
|
||||
logger.debug("BundleStateMetric is being bound...");
|
||||
this.meterRegistry = meterRegistry;
|
||||
Stream.of(bundleContext.getBundles()).forEach(bundle -> {
|
||||
createOrUpdateMetricForBundleState(bundle.getSymbolicName(), bundle.getState());
|
||||
});
|
||||
bundleContext.addBundleListener(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void bundleChanged(BundleEvent bundleEvent) {
|
||||
if (meterRegistry == null) {
|
||||
return;
|
||||
}
|
||||
String bundleName = bundleEvent.getBundle().getSymbolicName();
|
||||
int state = bundleEvent.getBundle().getState();
|
||||
createOrUpdateMetricForBundleState(bundleName, state);
|
||||
}
|
||||
|
||||
private void createOrUpdateMetricForBundleState(String bundleName, int state) {
|
||||
Meter.Id uniqueId = commonMeterId.withTag(Tag.of(BUNDLE_TAG_NAME, bundleName));
|
||||
AtomicInteger bundleStateHolder = registeredMeters.get(uniqueId);
|
||||
if (bundleStateHolder == null) {
|
||||
bundleStateHolder = new AtomicInteger();
|
||||
Gauge.builder(uniqueId.getName(), bundleStateHolder, AtomicInteger::get).baseUnit(uniqueId.getBaseUnit())
|
||||
.description(uniqueId.getDescription()).tags(uniqueId.getTags()).register(meterRegistry);
|
||||
registeredMeters.put(uniqueId, bundleStateHolder);
|
||||
}
|
||||
bundleStateHolder.set(state);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unbind() {
|
||||
if (meterRegistry == null) {
|
||||
return;
|
||||
}
|
||||
bundleContext.removeBundleListener(this);
|
||||
registeredMeters.keySet().forEach(meterRegistry::remove);
|
||||
registeredMeters.clear();
|
||||
meterRegistry = null;
|
||||
}
|
||||
}
|
@ -0,0 +1,113 @@
|
||||
/**
|
||||
* 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.core.io.monitor.internal.metrics;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Dictionary;
|
||||
import java.util.HashSet;
|
||||
import java.util.Hashtable;
|
||||
import java.util.Set;
|
||||
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.core.events.Event;
|
||||
import org.openhab.core.events.EventFilter;
|
||||
import org.openhab.core.events.EventSubscriber;
|
||||
import org.openhab.core.items.events.ItemCommandEvent;
|
||||
import org.openhab.core.items.events.ItemStateEvent;
|
||||
import org.osgi.framework.BundleContext;
|
||||
import org.osgi.framework.ServiceRegistration;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import io.micrometer.core.instrument.Meter;
|
||||
import io.micrometer.core.instrument.MeterRegistry;
|
||||
import io.micrometer.core.instrument.Tag;
|
||||
|
||||
/**
|
||||
* The {@link EventCountMetric} class implements a gauge metric for the openHAB events count (per topic)
|
||||
* topic.
|
||||
*
|
||||
* @author Robert Bach - Initial contribution
|
||||
*/
|
||||
public class EventCountMetric implements OpenhabCoreMeterBinder, EventSubscriber {
|
||||
|
||||
public static final String METRIC_NAME = "event_count";
|
||||
private final Logger logger = LoggerFactory.getLogger(EventCountMetric.class);
|
||||
private static final Tag CORE_EVENT_COUNT_METRIC_TAG = Tag.of("metric", "openhab.core.metric.eventcount");
|
||||
private static final String TOPIC_TAG_NAME = "topic";
|
||||
@Nullable
|
||||
private MeterRegistry meterRegistry;
|
||||
private final Set<Tag> tags = new HashSet<>();
|
||||
private ServiceRegistration<?> eventSubscriberRegistration;
|
||||
private BundleContext bundleContext;
|
||||
|
||||
public EventCountMetric(BundleContext bundleContext, Collection<Tag> tags) {
|
||||
this.tags.addAll(tags);
|
||||
this.tags.add(CORE_EVENT_COUNT_METRIC_TAG);
|
||||
this.bundleContext = bundleContext;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void bindTo(MeterRegistry meterRegistry) {
|
||||
unbind();
|
||||
logger.debug("EventCountMetric is being bound...");
|
||||
this.meterRegistry = meterRegistry;
|
||||
Dictionary<String, Object> properties = new Hashtable<>();
|
||||
properties.put("event.topics", "openhab/*");
|
||||
this.eventSubscriberRegistration = this.bundleContext.registerService(EventSubscriber.class.getName(), this,
|
||||
properties);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unbind() {
|
||||
if (meterRegistry == null) {
|
||||
return;
|
||||
}
|
||||
for (Meter meter : meterRegistry.getMeters()) {
|
||||
if (meter.getId().getTags().contains(CORE_EVENT_COUNT_METRIC_TAG)) {
|
||||
meterRegistry.remove(meter);
|
||||
}
|
||||
}
|
||||
meterRegistry = null;
|
||||
if (this.eventSubscriberRegistration != null) {
|
||||
this.eventSubscriberRegistration.unregister();
|
||||
this.eventSubscriberRegistration = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> getSubscribedEventTypes() {
|
||||
HashSet<String> subscribedEvents = new HashSet<>();
|
||||
subscribedEvents.add(ItemCommandEvent.TYPE);
|
||||
subscribedEvents.add(ItemStateEvent.TYPE);
|
||||
return subscribedEvents;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable EventFilter getEventFilter() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void receive(Event event) {
|
||||
if (meterRegistry == null) {
|
||||
logger.trace("Measurement not started. Skipping event processing");
|
||||
return;
|
||||
}
|
||||
String topic = event.getTopic();
|
||||
logger.debug("Received event on topic {}.", topic);
|
||||
Set<Tag> tagsWithTopic = new HashSet<>(tags);
|
||||
tagsWithTopic.add(Tag.of(TOPIC_TAG_NAME, topic));
|
||||
meterRegistry.counter(METRIC_NAME, tagsWithTopic).increment();
|
||||
}
|
||||
}
|
@ -0,0 +1,74 @@
|
||||
/**
|
||||
* 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.core.io.monitor.internal.metrics;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import io.micrometer.core.instrument.Meter;
|
||||
import io.micrometer.core.instrument.MeterRegistry;
|
||||
import io.micrometer.core.instrument.Tag;
|
||||
import io.micrometer.core.instrument.binder.jvm.ClassLoaderMetrics;
|
||||
import io.micrometer.core.instrument.binder.jvm.JvmGcMetrics;
|
||||
import io.micrometer.core.instrument.binder.jvm.JvmMemoryMetrics;
|
||||
import io.micrometer.core.instrument.binder.jvm.JvmThreadMetrics;
|
||||
import io.micrometer.core.instrument.binder.system.ProcessorMetrics;
|
||||
|
||||
/**
|
||||
* The {@link JVMMetric} class implements JVM related metrics like class loading, memory, GC and thread figures
|
||||
*
|
||||
* @author Robert Bach - Initial contribution
|
||||
*/
|
||||
public class JVMMetric implements OpenhabCoreMeterBinder {
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(JVMMetric.class);
|
||||
private static final Tag CORE_JVM_METRIC_TAG = Tag.of("metric", "openhab.core.metric.jvm");
|
||||
private final Set<Tag> tags = new HashSet<>();
|
||||
@Nullable
|
||||
private MeterRegistry meterRegistry;
|
||||
|
||||
public JVMMetric(Collection<Tag> tags) {
|
||||
this.tags.addAll(tags);
|
||||
this.tags.add(CORE_JVM_METRIC_TAG);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void bindTo(MeterRegistry registry) {
|
||||
unbind();
|
||||
logger.debug("JVMMetric is being bound...");
|
||||
this.meterRegistry = registry;
|
||||
new ClassLoaderMetrics(tags).bindTo(meterRegistry);
|
||||
new JvmMemoryMetrics(tags).bindTo(meterRegistry);
|
||||
new JvmGcMetrics(tags).bindTo(meterRegistry);
|
||||
new ProcessorMetrics(tags).bindTo(meterRegistry);
|
||||
new JvmThreadMetrics(tags).bindTo(meterRegistry);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unbind() {
|
||||
if (meterRegistry == null) {
|
||||
return;
|
||||
}
|
||||
for (Meter meter : meterRegistry.getMeters()) {
|
||||
if (meter.getId().getTags().contains(CORE_JVM_METRIC_TAG)) {
|
||||
meterRegistry.remove(meter);
|
||||
}
|
||||
}
|
||||
meterRegistry = null;
|
||||
}
|
||||
}
|
@ -0,0 +1,27 @@
|
||||
/**
|
||||
* 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.core.io.monitor.internal.metrics;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
|
||||
import io.micrometer.core.instrument.binder.MeterBinder;
|
||||
|
||||
/**
|
||||
* The {@link OpenhabCoreMeterBinder} interface provides an abstraction of the OH default metrics
|
||||
*
|
||||
* @author Robert Bach - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public interface OpenhabCoreMeterBinder extends MeterBinder {
|
||||
void unbind();
|
||||
}
|
@ -0,0 +1,120 @@
|
||||
/**
|
||||
* 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.core.io.monitor.internal.metrics;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Dictionary;
|
||||
import java.util.HashSet;
|
||||
import java.util.Hashtable;
|
||||
import java.util.Set;
|
||||
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.core.automation.RuleStatus;
|
||||
import org.openhab.core.automation.events.RuleStatusInfoEvent;
|
||||
import org.openhab.core.events.Event;
|
||||
import org.openhab.core.events.EventFilter;
|
||||
import org.openhab.core.events.EventSubscriber;
|
||||
import org.osgi.framework.BundleContext;
|
||||
import org.osgi.framework.ServiceRegistration;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import io.micrometer.core.instrument.Meter;
|
||||
import io.micrometer.core.instrument.MeterRegistry;
|
||||
import io.micrometer.core.instrument.Tag;
|
||||
|
||||
/**
|
||||
* The {@link RuleMetric} class implements a gauge metric for rules RUNNING events (per rule)
|
||||
*
|
||||
* @author Robert Bach - Initial contribution
|
||||
*/
|
||||
public class RuleMetric implements OpenhabCoreMeterBinder, EventSubscriber {
|
||||
|
||||
public static final String METRIC_NAME = "openhab.rule.runs";
|
||||
public static final String RULES_TOPIC_PREFIX = "openhab/rules/";
|
||||
public static final String RULES_TOPIC_SUFFIX = "/state";
|
||||
public static final String SUBSCRIPTION_PROPERTY_TOPIC = "event.topics";
|
||||
public static final String RULES_TOPIC_FILTER = "openhab/rules/*";
|
||||
private final Logger logger = LoggerFactory.getLogger(RuleMetric.class);
|
||||
private static final Tag CORE_RULE_METRIC_TAG = Tag.of("metric", "openhab.core.metric.rules");
|
||||
private static final String RULE_TAG_NAME = "rule";
|
||||
private @Nullable MeterRegistry meterRegistry;
|
||||
private final Set<Tag> tags = new HashSet<>();
|
||||
private ServiceRegistration<?> eventSubscriberRegistration;
|
||||
private BundleContext bundleContext;
|
||||
|
||||
public RuleMetric(BundleContext bundleContext, Collection<Tag> tags) {
|
||||
this.tags.addAll(tags);
|
||||
this.tags.add(CORE_RULE_METRIC_TAG);
|
||||
this.bundleContext = bundleContext;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void bindTo(@io.micrometer.core.lang.NonNull MeterRegistry meterRegistry) {
|
||||
unbind();
|
||||
logger.debug("RuleMetric is being bound...");
|
||||
this.meterRegistry = meterRegistry;
|
||||
Dictionary<String, Object> properties = new Hashtable<>();
|
||||
properties.put(SUBSCRIPTION_PROPERTY_TOPIC, RULES_TOPIC_FILTER);
|
||||
this.eventSubscriberRegistration = this.bundleContext.registerService(EventSubscriber.class.getName(), this,
|
||||
properties);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unbind() {
|
||||
if (meterRegistry == null) {
|
||||
return;
|
||||
}
|
||||
for (Meter meter : meterRegistry.getMeters()) {
|
||||
if (meter.getId().getTags().contains(CORE_RULE_METRIC_TAG)) {
|
||||
meterRegistry.remove(meter);
|
||||
}
|
||||
}
|
||||
meterRegistry = null;
|
||||
if (this.eventSubscriberRegistration != null) {
|
||||
this.eventSubscriberRegistration.unregister();
|
||||
this.eventSubscriberRegistration = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> getSubscribedEventTypes() {
|
||||
HashSet<String> subscribedEvents = new HashSet<>();
|
||||
subscribedEvents.add(RuleStatusInfoEvent.TYPE);
|
||||
return subscribedEvents;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable EventFilter getEventFilter() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void receive(Event event) {
|
||||
if (meterRegistry == null) {
|
||||
logger.trace("Measurement not started. Skipping rule event processing");
|
||||
return;
|
||||
}
|
||||
String topic = event.getTopic();
|
||||
String rule = topic.substring(RULES_TOPIC_PREFIX.length(), topic.indexOf(RULES_TOPIC_SUFFIX));
|
||||
if (!event.getPayload().contains(RuleStatus.RUNNING.name())) {
|
||||
logger.trace("Skipping rule status info with status other than RUNNING {}", event.getPayload());
|
||||
return;
|
||||
}
|
||||
|
||||
logger.debug("Rule {} RUNNING - updating metric.", rule);
|
||||
Set<Tag> tagsWithRule = new HashSet<>(tags);
|
||||
tagsWithRule.add(Tag.of(RULE_TAG_NAME, rule));
|
||||
meterRegistry.counter(METRIC_NAME, tagsWithRule).increment();
|
||||
}
|
||||
}
|
@ -0,0 +1,125 @@
|
||||
/**
|
||||
* 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.core.io.monitor.internal.metrics;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Dictionary;
|
||||
import java.util.HashMap;
|
||||
import java.util.Hashtable;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.core.events.Event;
|
||||
import org.openhab.core.events.EventFilter;
|
||||
import org.openhab.core.events.EventSubscriber;
|
||||
import org.openhab.core.thing.ThingRegistry;
|
||||
import org.openhab.core.thing.ThingStatus;
|
||||
import org.openhab.core.thing.ThingStatusInfo;
|
||||
import org.openhab.core.thing.events.ThingStatusInfoEvent;
|
||||
import org.osgi.framework.BundleContext;
|
||||
import org.osgi.framework.ServiceRegistration;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
|
||||
import io.micrometer.core.instrument.Gauge;
|
||||
import io.micrometer.core.instrument.Meter;
|
||||
import io.micrometer.core.instrument.MeterRegistry;
|
||||
import io.micrometer.core.instrument.Tag;
|
||||
import io.micrometer.core.instrument.Tags;
|
||||
|
||||
/**
|
||||
* The {@link ThingStateMetric} class implements a metric for the openHAB things states.
|
||||
*
|
||||
* @author Robert Bach - Initial contribution
|
||||
*/
|
||||
public class ThingStateMetric implements OpenhabCoreMeterBinder, EventSubscriber {
|
||||
private final Logger logger = LoggerFactory.getLogger(ThingStateMetric.class);
|
||||
public static final String METRIC_NAME = "openhab.thing.state";
|
||||
private static final String THING_TAG_NAME = "thing";
|
||||
private static final String THINGSTATUS_TOPIC_PREFIX = "openhab/things/";
|
||||
private final ThingRegistry thingRegistry;
|
||||
private final Meter.Id commonMeterId;
|
||||
private final Map<Meter.Id, AtomicInteger> registeredMeters = new HashMap<>();
|
||||
private @Nullable MeterRegistry meterRegistry;
|
||||
private @Nullable ServiceRegistration<?> eventSubscriberRegistration;
|
||||
private final BundleContext bundleContext;
|
||||
private final Gson gson = new Gson();
|
||||
|
||||
public ThingStateMetric(BundleContext bundleContext, ThingRegistry thingRegistry, Collection<Tag> tags) {
|
||||
this.bundleContext = bundleContext;
|
||||
this.thingRegistry = thingRegistry;
|
||||
commonMeterId = new Meter.Id(METRIC_NAME, Tags.of(tags), "state", "openHAB thing state", Meter.Type.GAUGE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void bindTo(@io.micrometer.core.lang.NonNull MeterRegistry meterRegistry) {
|
||||
unbind();
|
||||
logger.debug("ThingStateMetric is being bound...");
|
||||
this.meterRegistry = meterRegistry;
|
||||
thingRegistry.getAll().forEach(
|
||||
thing -> createOrUpdateMetricForBundleState(thing.getUID().getId(), thing.getStatus().ordinal()));
|
||||
Dictionary<String, Object> properties = new Hashtable<>();
|
||||
properties.put("event.topics", "openhab/things/*");
|
||||
this.eventSubscriberRegistration = this.bundleContext.registerService(EventSubscriber.class.getName(), this,
|
||||
properties);
|
||||
}
|
||||
|
||||
private void createOrUpdateMetricForBundleState(String thingUid, int thingStatus) {
|
||||
Meter.Id uniqueId = commonMeterId.withTag(Tag.of(THING_TAG_NAME, thingUid));
|
||||
AtomicInteger thingStateHolder = registeredMeters.get(uniqueId);
|
||||
if (thingStateHolder == null) {
|
||||
thingStateHolder = new AtomicInteger();
|
||||
Gauge.builder(uniqueId.getName(), thingStateHolder, AtomicInteger::get).baseUnit(uniqueId.getBaseUnit())
|
||||
.description(uniqueId.getDescription()).tags(uniqueId.getTags()).register(meterRegistry);
|
||||
registeredMeters.put(uniqueId, thingStateHolder);
|
||||
}
|
||||
thingStateHolder.set(thingStatus);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unbind() {
|
||||
if (meterRegistry == null) {
|
||||
return;
|
||||
}
|
||||
if (eventSubscriberRegistration != null) {
|
||||
eventSubscriberRegistration.unregister();
|
||||
eventSubscriberRegistration = null;
|
||||
}
|
||||
registeredMeters.keySet().forEach(meterRegistry::remove);
|
||||
registeredMeters.clear();
|
||||
meterRegistry = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> getSubscribedEventTypes() {
|
||||
return Set.of(ThingStatusInfoEvent.TYPE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable EventFilter getEventFilter() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void receive(Event event) {
|
||||
logger.trace("Received ThingStatusInfo(Changed)Event...");
|
||||
String thingId = event.getTopic().substring(THINGSTATUS_TOPIC_PREFIX.length(),
|
||||
event.getTopic().lastIndexOf('/'));
|
||||
ThingStatus status = gson.fromJson(event.getPayload(), ThingStatusInfo.class).getStatus();
|
||||
createOrUpdateMetricForBundleState(thingId, status.ordinal());
|
||||
}
|
||||
}
|
@ -0,0 +1,83 @@
|
||||
/**
|
||||
* 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.core.io.monitor.internal.metrics;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.core.common.ThreadPoolManager;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import io.micrometer.core.instrument.Meter;
|
||||
import io.micrometer.core.instrument.MeterRegistry;
|
||||
import io.micrometer.core.instrument.Tag;
|
||||
import io.micrometer.core.instrument.binder.jvm.ExecutorServiceMetrics;
|
||||
|
||||
/**
|
||||
* The {@link ThreadPoolMetric} class implements a set of metrics for ThreadManager thread pool stats
|
||||
*
|
||||
* @author Robert Bach - Initial contribution
|
||||
*/
|
||||
public class ThreadPoolMetric implements OpenhabCoreMeterBinder {
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(ThreadPoolMetric.class);
|
||||
public static final Tag CORE_THREADPOOL_METRIC_TAG = Tag.of("metric", "openhab.core.metric.threadpools");
|
||||
private static final String POOLNAME_TAG_NAME = "pool";
|
||||
private final Set<Tag> tags = new HashSet<>();
|
||||
@Nullable
|
||||
private MeterRegistry meterRegistry;
|
||||
|
||||
public ThreadPoolMetric(Collection<Tag> tags) {
|
||||
this.tags.addAll(tags);
|
||||
this.tags.add(CORE_THREADPOOL_METRIC_TAG);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void bindTo(MeterRegistry registry) {
|
||||
unbind();
|
||||
logger.debug("ThreadPoolMetric is being bound...");
|
||||
this.meterRegistry = registry;
|
||||
try {
|
||||
ThreadPoolManager.getPoolNames().forEach(this::addPoolMetrics);
|
||||
} catch (NoSuchMethodError nsme) {
|
||||
logger.info("A newer version of openHAB is required for thread pool metrics to work.");
|
||||
}
|
||||
}
|
||||
|
||||
private void addPoolMetrics(String poolName) {
|
||||
ExecutorService es = ThreadPoolManager.getPool(poolName);
|
||||
if (es == null) {
|
||||
return;
|
||||
}
|
||||
Set<Tag> tagsWithPoolname = new HashSet<>(tags);
|
||||
tagsWithPoolname.add(Tag.of(POOLNAME_TAG_NAME, poolName));
|
||||
new ExecutorServiceMetrics(es, poolName, tagsWithPoolname).bindTo(meterRegistry);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unbind() {
|
||||
if (meterRegistry == null) {
|
||||
return;
|
||||
}
|
||||
for (Meter meter : meterRegistry.getMeters()) {
|
||||
if (meter.getId().getTags().contains(CORE_THREADPOOL_METRIC_TAG)) {
|
||||
meterRegistry.remove(meter);
|
||||
}
|
||||
}
|
||||
meterRegistry = null;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user