001package io.prometheus.metrics.core.metrics;
002
003import io.prometheus.metrics.config.PrometheusProperties;
004import io.prometheus.metrics.model.snapshots.Exemplars;
005import io.prometheus.metrics.model.snapshots.Quantiles;
006import io.prometheus.metrics.model.snapshots.SummarySnapshot;
007
008import java.util.ArrayList;
009import java.util.Collections;
010import java.util.List;
011import java.util.function.Consumer;
012
013/**
014 * Example:
015 * <pre>{@code
016 * double MILLISECONDS_PER_SECOND = 1E3;
017 *
018 * SummaryWithCallback.builder()
019 *         .name("jvm_gc_collection_seconds")
020 *         .help("Time spent in a given JVM garbage collector in seconds.")
021 *         .unit(Unit.SECONDS)
022 *         .labelNames("gc")
023 *         .callback(callback -> {
024 *             for (GarbageCollectorMXBean gc : ManagementFactory.getGarbageCollectorMXBeans()) {
025 *                 callback.call(
026 *                         gc.getCollectionCount(),
027 *                         gc.getCollectionTime() / MILLISECONDS_PER_SECOND,
028 *                         Quantiles.EMPTY,
029 *                         gc.getName()
030 *                 );
031 *             }
032 *         })
033 *         .register();
034 * }</pre>
035 */
036public class SummaryWithCallback extends CallbackMetric {
037
038    @FunctionalInterface
039    public interface Callback {
040        void call(long count, double sum, Quantiles quantiles, String... labelValues);
041    }
042
043    private final Consumer<Callback> callback;
044
045    private SummaryWithCallback(Builder builder) {
046        super(builder);
047        this.callback = builder.callback;
048        if (callback == null) {
049            throw new IllegalArgumentException("callback cannot be null");
050        }
051    }
052
053    @Override
054    public SummarySnapshot collect() {
055        List<SummarySnapshot.SummaryDataPointSnapshot> dataPoints = new ArrayList<>();
056        callback.accept((count, sum, quantiles, labelValues) -> {
057            dataPoints.add(new SummarySnapshot.SummaryDataPointSnapshot(count, sum, quantiles, makeLabels(labelValues), Exemplars.EMPTY, 0L));
058        });
059        return new SummarySnapshot(getMetadata(), dataPoints);
060    }
061
062    public static Builder builder() {
063        return new Builder(PrometheusProperties.get());
064    }
065
066    public static Builder builder(PrometheusProperties properties) {
067        return new Builder(properties);
068    }
069
070    public static class Builder extends CallbackMetric.Builder<SummaryWithCallback.Builder, SummaryWithCallback> {
071
072        private Consumer<Callback> callback;
073
074        public Builder callback(Consumer<Callback> callback) {
075            this.callback = callback;
076            return self();
077        }
078
079        private Builder(PrometheusProperties properties) {
080            super(Collections.singletonList("quantile"), properties);
081        }
082
083        @Override
084        public SummaryWithCallback build() {
085            return new SummaryWithCallback(this);
086        }
087
088        @Override
089        protected Builder self() {
090            return this;
091        }
092    }
093}