All Downloads are FREE. Search and download functionalities are using the official Maven repository.

sirius.kernel.health.metrics.Metrics Maven / Gradle / Ivy

Go to download

Provides common core classes and the microkernel powering all Sirius applications

There is a newer version: 12.9.1
Show newest version
/*
 * Made with all the love in the world
 * by scireum in Remshalden, Germany
 *
 * Copyright by scireum GmbH
 * http://www.scireum.de - [email protected]
 */

package sirius.kernel.health.metrics;

import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import sirius.kernel.Sirius;
import sirius.kernel.async.Tasks;
import sirius.kernel.commons.DataCollector;
import sirius.kernel.di.std.Part;
import sirius.kernel.di.std.Parts;
import sirius.kernel.di.std.Register;
import sirius.kernel.health.Exceptions;
import sirius.kernel.health.Log;
import sirius.kernel.timer.EveryMinute;

import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;

/**
 * Collects and stores metrics for various parts of the system.
 * 

* To provide custom metrics, implement {@link MetricProvider} and register it in the component model using the * {@link Register} annotation. *

* The collected metrics are updated once every minute. */ @Register(classes = {Metrics.class, EveryMinute.class}) public class Metrics implements EveryMinute { private static final String HEALTH_LIMITS_PREFIX = "health.limits."; private static final String LIMIT_TYPE_GRAY = ".gray"; private static final String LIMIT_TYPE_WARNING = ".warning"; private static final String LIMIT_TYPE_ERROR = ".error"; @Parts(MetricProvider.class) private Collection providers; /** * Contains all limits as defined in the system config */ private Map limits = Maps.newHashMap(); /** * Contains the last value of each metric in order to compute differential metrics */ private Map differentials = Maps.newHashMap(); @Part private Tasks tasks; /** * Contains all collected metrics */ private List metricsList = Lists.newArrayList(); /** * Internal structure to combine the three limits available for each metric: gray, warning (yellow), error (red). */ private static class Limit { double gray = 0; double yellow = 0; double red = 0; @Override public String toString() { return "(" + gray + " / " + yellow + " / " + red + ")"; } } /** * Provides an adapter from DataCollector to MetricsCollector. */ private class MetricCollectorAdapter implements MetricsCollector { private DataCollector collector; private MetricCollectorAdapter(DataCollector collector) { this.collector = collector; } @Override public void metric(String code, String label, double value, String unit, MetricState state) { collector.add(new Metric(code, label, value, state, unit)); } @Override public void metric(String code, String limitType, String label, double value, String unit) { collector.add(new Metric(code, label, value, computeState(limitType, value), unit)); } @Override public void differentialMetric(String code, String limitType, String label, double currentValue, String unit) { Double lastValue = differentials.get(code); if (lastValue != null) { metric(code, limitType, label, currentValue - lastValue, unit); } differentials.put(code, currentValue); } /* * Computes the state of the metric based in the limits given in the config */ private MetricState computeState(String limitType, double value) { Limit limit = limits.computeIfAbsent(limitType, this::loadLimit); if (value <= limit.gray) { return MetricState.GRAY; } if (limit.red > 0 && value >= limit.red) { return MetricState.RED; } if (limit.yellow > 0 && value >= limit.yellow) { return MetricState.YELLOW; } return MetricState.GREEN; } private Limit loadLimit(String limitType) { Limit limit = new Limit(); String configPrefix = HEALTH_LIMITS_PREFIX + limitType; if (Sirius.getSettings().getConfig().hasPath(configPrefix + LIMIT_TYPE_GRAY)) { limit.gray = Sirius.getSettings().getConfig().getDouble(configPrefix + LIMIT_TYPE_GRAY); } if (Sirius.getSettings().getConfig().hasPath(configPrefix + LIMIT_TYPE_WARNING)) { limit.yellow = Sirius.getSettings().getConfig().getDouble(configPrefix + LIMIT_TYPE_WARNING); } if (Sirius.getSettings().getConfig().hasPath(configPrefix + ".warn")) { Log.SYSTEM.WARN("Invalid metrics limit: '%s' - Use: '%s' instead", configPrefix + ".warn", configPrefix + LIMIT_TYPE_WARNING); } if (Sirius.getSettings().getConfig().hasPath(configPrefix + LIMIT_TYPE_ERROR)) { limit.red = Sirius.getSettings().getConfig().getDouble(configPrefix + LIMIT_TYPE_ERROR); } return limit; } } @Override public synchronized void runTimer() throws Exception { tasks.defaultExecutor().start(this::collectMetrics); } private void collectMetrics() { final DataCollector collector = DataCollector.create(); for (MetricProvider provider : providers) { collectMetrics(collector, provider); } List newMetricsList = collector.getData(); Collections.sort(newMetricsList); metricsList = newMetricsList; } private void collectMetrics(DataCollector collector, MetricProvider provider) { try { provider.gather(new MetricCollectorAdapter(collector)); } catch (Exception e) { Exceptions.handle(e); } } /** * Returns a list of all collected metrics so far. * * @return a list of all metrics */ public List getMetrics() { return Collections.unmodifiableList(metricsList); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy