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

org.restheart.metrics.RHDropwizardExports Maven / Gradle / Ivy

There is a newer version: 8.1.6
Show newest version
package org.restheart.metrics;

import com.codahale.metrics.Counter;
import com.codahale.metrics.Gauge;
import com.codahale.metrics.Histogram;
import com.codahale.metrics.Meter;
import com.codahale.metrics.Metric;
import com.codahale.metrics.MetricFilter;
import com.codahale.metrics.MetricRegistry;
import com.codahale.metrics.SharedMetricRegistries;
import com.codahale.metrics.Snapshot;
import com.codahale.metrics.Timer;
import io.prometheus.client.dropwizard.samplebuilder.SampleBuilder;
import io.prometheus.client.Collector.MetricFamilySamples.Sample;
import io.prometheus.client.dropwizard.samplebuilder.DefaultSampleBuilder;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.SortedMap;
import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * Collect Dropwizard metrics from a MetricRegistry.
 *
 * Modified from https://github.com/prometheus/client_java/blob/main/simpleclient_dropwizard/src/main/java/io/prometheus/client/dropwizard/DropwizardExports.java
 * to track additional timer metrics and to handle metric name as MetricNameAndLabels
 */
public class RHDropwizardExports extends io.prometheus.client.Collector implements io.prometheus.client.Collector.Describable {
    private static final Logger LOGGER = Logger.getLogger(RHDropwizardExports.class.getName());
    private MetricRegistry registry;
    private MetricFilter metricFilter;
    private SampleBuilder sampleBuilder;

    /**
     * Creates a new DropwizardExports with a {@link DefaultSampleBuilder} and {@link MetricFilter#ALL}.
     *
     * @param registry a metric registry to export in prometheus.
     */
    public RHDropwizardExports(String registryName) {
        this(SharedMetricRegistries.getOrCreate(registryName));
    }

    /**
     * Creates a new DropwizardExports with a {@link DefaultSampleBuilder} and {@link MetricFilter#ALL}.
     *
     * @param registry a metric registry to export in prometheus.
     */
    public RHDropwizardExports(MetricRegistry registry) {
        this.registry = registry;
        this.metricFilter = MetricFilter.ALL;
        this.sampleBuilder = new RHSampler();
    }

    private static String getHelpMessage(String metricName, Metric metric) {
        return String.format("Generated from Dropwizard metric import (metric=%s, type=%s)", metricName, metric.getClass().getName());
    }

    /**
     * Export counter as Prometheus Gauge.
     */
    MetricFamilySamples fromCounter(String dropwizardName, Counter counter) {
        MetricFamilySamples.Sample sample = sampleBuilder.createSample(dropwizardName, "", new ArrayList(), new ArrayList(), Long.valueOf(counter.getCount()).doubleValue());
        return new MetricFamilySamples(sample.name, Type.GAUGE, getHelpMessage(dropwizardName, counter), Arrays.asList(sample));
    }

    /**
     * Export gauge as a prometheus gauge.
     */
    MetricFamilySamples fromGauge(String dropwizardName, Gauge gauge) {
        Object obj = gauge.getValue();
        double value;
        if (obj instanceof Number) {
            value = ((Number) obj).doubleValue();
        } else if (obj instanceof Boolean) {
            value = ((Boolean) obj) ? 1 : 0;
        } else {
            LOGGER.log(Level.FINE, String.format("Invalid type for Gauge %s: %s", sanitizeMetricName(dropwizardName), obj == null ? "null" : obj.getClass().getName()));
            return null;
        }
        MetricFamilySamples.Sample sample = sampleBuilder.createSample(dropwizardName, "", new ArrayList(), new ArrayList(), value);
        return new MetricFamilySamples(sample.name, Type.GAUGE, getHelpMessage(dropwizardName, gauge), Arrays.asList(sample));
    }

    /**
     * Export a histogram snapshot as a prometheus SUMMARY.
     *
     * @param dropwizardName metric name.
     * @param snapshot       the histogram snapshot.
     * @param count          the total sample count for this snapshot.
     * @param factor         a factor to apply to histogram values.
     */
    MetricFamilySamples fromSnapshotAndCount(String dropwizardName, Snapshot snapshot, long count, double factor, String helpMessage) {
        List samples = Arrays.asList(
                sampleBuilder.createSample(dropwizardName, "", Arrays.asList("quantile"), Arrays.asList("0.5"), snapshot.getMedian() * factor),
                sampleBuilder.createSample(dropwizardName, "", Arrays.asList("quantile"), Arrays.asList("0.75"), snapshot.get75thPercentile() * factor),
                sampleBuilder.createSample(dropwizardName, "", Arrays.asList("quantile"), Arrays.asList("0.95"), snapshot.get95thPercentile() * factor),
                sampleBuilder.createSample(dropwizardName, "", Arrays.asList("quantile"), Arrays.asList("0.98"), snapshot.get98thPercentile() * factor),
                sampleBuilder.createSample(dropwizardName, "", Arrays.asList("quantile"), Arrays.asList("0.99"), snapshot.get99thPercentile() * factor),
                sampleBuilder.createSample(dropwizardName, "", Arrays.asList("quantile"), Arrays.asList("0.999"), snapshot.get999thPercentile() * factor),
                sampleBuilder.createSample(dropwizardName, "_count", new ArrayList(), new ArrayList(), count)
        );
        return new MetricFamilySamples(samples.get(0).name, Type.SUMMARY, helpMessage, samples);
    }

    MetricFamilySamples fromTimer(String dropwizardName, Timer timer, String helpMessage) {
        var snapshot = timer.getSnapshot();

        List samples = Arrays.asList(
                this.sampleBuilder.createSample(dropwizardName, "_duration", Arrays.asList("quantile"), Arrays.asList("0.5"), snapshot.getMedian() * TIMER_FACTOR),
                this.sampleBuilder.createSample(dropwizardName, "_duration", Arrays.asList("quantile"), Arrays.asList("0.75"), snapshot.get75thPercentile() * TIMER_FACTOR),
                this.sampleBuilder.createSample(dropwizardName, "_duration", Arrays.asList("quantile"), Arrays.asList("0.95"), snapshot.get95thPercentile() * TIMER_FACTOR),
                this.sampleBuilder.createSample(dropwizardName, "_duration", Arrays.asList("quantile"), Arrays.asList("0.98"), snapshot.get98thPercentile() * TIMER_FACTOR),
                this.sampleBuilder.createSample(dropwizardName, "_duration", Arrays.asList("quantile"), Arrays.asList("0.99"), snapshot.get99thPercentile() * TIMER_FACTOR),
                this.sampleBuilder.createSample(dropwizardName, "_duration", Arrays.asList("quantile"), Arrays.asList("0.999"), snapshot.get999thPercentile() * TIMER_FACTOR),

                this.sampleBuilder.createSample(dropwizardName, "_rate", Arrays.asList("period"), Arrays.asList("15 minutes"), timer.getFifteenMinuteRate()),
                this.sampleBuilder.createSample(dropwizardName, "_rate", Arrays.asList("period"), Arrays.asList("5 minutes"), timer.getFiveMinuteRate()),
                this.sampleBuilder.createSample(dropwizardName, "_rate", Arrays.asList("period"), Arrays.asList("1 minute"), timer.getOneMinuteRate()),
                this.sampleBuilder.createSample(dropwizardName, "_rate", Arrays.asList("period"), Arrays.asList("overall"), timer.getMeanRate()),


                this.sampleBuilder.createSample(dropwizardName, "_count", new ArrayList(), new ArrayList(), timer.getCount())
        );
        return new MetricFamilySamples(samples.get(0).name, Type.SUMMARY, helpMessage, samples);
    }

    /**
     * Convert histogram snapshot.
     */
    MetricFamilySamples fromHistogram(String dropwizardName, Histogram histogram) {
        return fromSnapshotAndCount(dropwizardName, histogram.getSnapshot(), histogram.getCount(), 1.0, getHelpMessage(dropwizardName, histogram));
    }

    private static double TIMER_FACTOR = 1.0D / TimeUnit.SECONDS.toNanos(1L);

    /**
     * Export Dropwizard Timer as a histogram. Use TIME_UNIT as time unit.
     */
    MetricFamilySamples fromTimer(String dropwizardName, Timer timer) {
        return fromTimer(dropwizardName, timer, getHelpMessage(dropwizardName, timer));
    }

    /**
     * Export a Meter as as prometheus COUNTER.
     */
    MetricFamilySamples fromMeter(String dropwizardName, Meter meter) {
        final MetricFamilySamples.Sample sample = sampleBuilder.createSample(dropwizardName, "_total",
                new ArrayList(),
                new ArrayList(),
                meter.getCount());
        return new MetricFamilySamples(sample.name, Type.COUNTER, getHelpMessage(dropwizardName, meter), Arrays.asList(sample));
    }

    @Override
    @SuppressWarnings("rawtypes")
    public List collect() {
        Map mfSamplesMap = new HashMap();

        for (SortedMap.Entry entry : registry.getGauges(metricFilter).entrySet()) {
            addToMap(mfSamplesMap, fromGauge(entry.getKey(), entry.getValue()));
        }
        for (SortedMap.Entry entry : registry.getCounters(metricFilter).entrySet()) {
            addToMap(mfSamplesMap, fromCounter(entry.getKey(), entry.getValue()));
        }
        for (SortedMap.Entry entry : registry.getHistograms(metricFilter).entrySet()) {
            addToMap(mfSamplesMap, fromHistogram(entry.getKey(), entry.getValue()));
        }
        for (SortedMap.Entry entry : registry.getTimers(metricFilter).entrySet()) {
            addToMap(mfSamplesMap, fromTimer(entry.getKey(), entry.getValue()));
        }
        for (SortedMap.Entry entry : registry.getMeters(metricFilter).entrySet()) {
            addToMap(mfSamplesMap, fromMeter(entry.getKey(), entry.getValue()));
        }
        return new ArrayList(mfSamplesMap.values());
    }

    private void addToMap(Map mfSamplesMap, MetricFamilySamples newMfSamples)
    {
        if (newMfSamples != null) {
            MetricFamilySamples currentMfSamples = mfSamplesMap.get(newMfSamples.name);
            if (currentMfSamples == null) {
                mfSamplesMap.put(newMfSamples.name, newMfSamples);
            } else {
                List samples = new ArrayList(currentMfSamples.samples);
                samples.addAll(newMfSamples.samples);
                mfSamplesMap.put(newMfSamples.name, new MetricFamilySamples(newMfSamples.name, currentMfSamples.type, currentMfSamples.help, samples));
            }
        }
    }

    @Override
    public List describe() {
        return new ArrayList();
    }

    private static class RHSampler implements SampleBuilder {
        private static DefaultSampleBuilder DSB = new DefaultSampleBuilder();

        @Override
        public Sample createSample(String dropwizardName, String nameSuffix, List additionalLabelNames, List additionalLabelValues, double value) {
            if (dropwizardName.startsWith("jvm")) {
                return DSB.createSample(dropwizardName, nameSuffix, additionalLabelNames, additionalLabelValues, value);
            } else {
                var nals = MetricNameAndLabels.from(dropwizardName);

                var _additionalLabelNames = new ArrayList();
                var _additionalLabelValues = new ArrayList();

                nals.labels().forEach(l -> {
                    _additionalLabelNames.add(l.name());
                    _additionalLabelValues.add(l.value());
                });

                _additionalLabelNames.addAll(additionalLabelNames);
                _additionalLabelValues.addAll(additionalLabelValues);

                return DSB.createSample(nals.name(), nameSuffix, _additionalLabelNames, _additionalLabelValues, value);
            }
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy