001package io.prometheus.metrics.core.metrics;
002
003import io.prometheus.metrics.annotations.StableApi;
004import io.prometheus.metrics.config.PrometheusProperties;
005import io.prometheus.metrics.model.registry.MetricType;
006import io.prometheus.metrics.model.snapshots.GaugeSnapshot;
007import java.util.ArrayList;
008import java.util.Collections;
009import java.util.List;
010import java.util.function.Consumer;
011import javax.annotation.Nullable;
012
013/**
014 * Example:
015 *
016 * <pre>{@code
017 * MemoryMXBean memoryBean = ManagementFactory.getMemoryMXBean();
018 *
019 * GaugeWithCallback.builder()
020 *     .name("jvm_memory_bytes_used")
021 *     .help("Used bytes of a given JVM memory area.")
022 *     .unit(Unit.BYTES)
023 *     .labelNames("area")
024 *     .callback(callback -> {
025 *         callback.call(memoryBean.getHeapMemoryUsage().getUsed(), "heap");
026 *         callback.call(memoryBean.getNonHeapMemoryUsage().getUsed(), "nonheap");
027 *     })
028 *     .register();
029 * }</pre>
030 */
031@StableApi
032public class GaugeWithCallback extends CallbackMetric {
033
034  @FunctionalInterface
035  public interface Callback {
036    void call(double value, String... labelValues);
037  }
038
039  private final Consumer<Callback> callback;
040
041  private GaugeWithCallback(Builder builder) {
042    super(builder);
043    if (builder.callback == null) {
044      throw new IllegalArgumentException("callback cannot be null");
045    }
046    this.callback = builder.callback;
047  }
048
049  @Override
050  public GaugeSnapshot collect() {
051    List<GaugeSnapshot.GaugeDataPointSnapshot> dataPoints = new ArrayList<>();
052    callback.accept(
053        (value, labelValues) -> {
054          dataPoints.add(
055              new GaugeSnapshot.GaugeDataPointSnapshot(value, makeLabels(labelValues), null, 0L));
056        });
057    return new GaugeSnapshot(metadata, dataPoints);
058  }
059
060  /**
061   * @deprecated Use {@link #getMetricFamilyDescriptor()} instead.
062   */
063  @Override
064  @Deprecated
065  @SuppressWarnings("InlineMeSuggester")
066  public MetricType getMetricType() {
067    return MetricType.GAUGE;
068  }
069
070  public static Builder builder() {
071    return new Builder(PrometheusProperties.get());
072  }
073
074  public static Builder builder(PrometheusProperties properties) {
075    return new Builder(properties);
076  }
077
078  public static class Builder
079      extends CallbackMetric.Builder<GaugeWithCallback.Builder, GaugeWithCallback> {
080
081    @Nullable private Consumer<Callback> callback;
082
083    public Builder callback(Consumer<Callback> callback) {
084      this.callback = callback;
085      return self();
086    }
087
088    private Builder(PrometheusProperties properties) {
089      super(Collections.emptyList(), properties);
090    }
091
092    @Override
093    public GaugeWithCallback build() {
094      return new GaugeWithCallback(this);
095    }
096
097    @Override
098    protected Builder self() {
099      return this;
100    }
101  }
102}