001package io.prometheus.metrics.model.snapshots;
002
003import io.prometheus.metrics.annotations.StableApi;
004import io.prometheus.metrics.config.EscapingScheme;
005import java.util.ArrayList;
006import java.util.Collection;
007import java.util.List;
008import javax.annotation.Nullable;
009
010/** Immutable snapshot of a Gauge. */
011@StableApi
012public final class GaugeSnapshot extends MetricSnapshot {
013
014  /**
015   * To create a new {@link GaugeSnapshot}, you can either call the constructor directly or use the
016   * builder with {@link GaugeSnapshot#builder()}.
017   *
018   * @param metadata see {@link MetricMetadata} for naming conventions.
019   * @param data the constructor will create a sorted copy of the collection.
020   */
021  public GaugeSnapshot(MetricMetadata metadata, Collection<GaugeDataPointSnapshot> data) {
022    this(metadata, data, false);
023  }
024
025  private GaugeSnapshot(
026      MetricMetadata metadata, Collection<GaugeDataPointSnapshot> data, boolean internal) {
027    super(metadata, data, internal);
028  }
029
030  @SuppressWarnings("unchecked")
031  @Override
032  public List<GaugeDataPointSnapshot> getDataPoints() {
033    return (List<GaugeDataPointSnapshot>) dataPoints;
034  }
035
036  @SuppressWarnings("unchecked")
037  @Override
038  MetricSnapshot escape(
039      EscapingScheme escapingScheme, List<? extends DataPointSnapshot> dataPointSnapshots) {
040    return new GaugeSnapshot(
041        getMetadata().escape(escapingScheme),
042        (List<GaugeDataPointSnapshot>) dataPointSnapshots,
043        true);
044  }
045
046  public static final class GaugeDataPointSnapshot extends DataPointSnapshot {
047
048    private final double value;
049    @Nullable private final Exemplar exemplar;
050
051    /**
052     * To create a new {@link GaugeDataPointSnapshot}, you can either call the constructor directly
053     * or use the Builder with {@link GaugeDataPointSnapshot#builder()}.
054     *
055     * @param value the gauge value.
056     * @param labels must not be null. Use {@link Labels#EMPTY} if there are no labels.
057     * @param exemplar may be null.
058     */
059    public GaugeDataPointSnapshot(double value, Labels labels, @Nullable Exemplar exemplar) {
060      this(value, labels, exemplar, 0);
061    }
062
063    /**
064     * Constructor with an additional scrape timestamp. This is only useful in rare cases as the
065     * scrape timestamp is usually set by the Prometheus server during scraping. Exceptions include
066     * mirroring metrics with given timestamps from other metric sources.
067     */
068    public GaugeDataPointSnapshot(
069        double value, Labels labels, @Nullable Exemplar exemplar, long scrapeTimestampMillis) {
070      this(value, labels, exemplar, scrapeTimestampMillis, false);
071    }
072
073    private GaugeDataPointSnapshot(
074        double value,
075        Labels labels,
076        @Nullable Exemplar exemplar,
077        long scrapeTimestampMillis,
078        boolean internal) {
079      super(labels, 0L, scrapeTimestampMillis, internal);
080      this.value = value;
081      this.exemplar = exemplar;
082    }
083
084    public double getValue() {
085      return value;
086    }
087
088    @Nullable
089    public Exemplar getExemplar() {
090      return exemplar;
091    }
092
093    public static Builder builder() {
094      return new Builder();
095    }
096
097    @Override
098    DataPointSnapshot escape(EscapingScheme escapingScheme) {
099      return new GaugeSnapshot.GaugeDataPointSnapshot(
100          value,
101          SnapshotEscaper.escapeLabels(getLabels(), escapingScheme),
102          SnapshotEscaper.escapeExemplar(exemplar, escapingScheme),
103          getCreatedTimestampMillis(),
104          true);
105    }
106
107    public static class Builder extends DataPointSnapshot.Builder<Builder> {
108
109      @Nullable private Exemplar exemplar = null;
110      @Nullable private Double value = null;
111
112      private Builder() {}
113
114      /** Gauge value. This is required. */
115      public Builder value(double value) {
116        this.value = value;
117        return this;
118      }
119
120      /** Optional */
121      public Builder exemplar(Exemplar exemplar) {
122        this.exemplar = exemplar;
123        return this;
124      }
125
126      public GaugeDataPointSnapshot build() {
127        if (value == null) {
128          throw new IllegalArgumentException("Missing required field: value is null.");
129        }
130        return new GaugeDataPointSnapshot(value, labels, exemplar, scrapeTimestampMillis);
131      }
132
133      @Override
134      protected Builder self() {
135        return this;
136      }
137    }
138  }
139
140  public static Builder builder() {
141    return new Builder();
142  }
143
144  public static class Builder extends MetricSnapshot.Builder<Builder> {
145
146    private final List<GaugeDataPointSnapshot> dataPoints = new ArrayList<>();
147
148    private Builder() {}
149
150    /** Add a data point. This can be called multiple times to add multiple data points. */
151    public Builder dataPoint(GaugeDataPointSnapshot dataPoint) {
152      dataPoints.add(dataPoint);
153      return this;
154    }
155
156    @Override
157    public GaugeSnapshot build() {
158      return new GaugeSnapshot(buildMetadata(), dataPoints);
159    }
160
161    @Override
162    protected Builder self() {
163      return this;
164    }
165  }
166}