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