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;
008
009/** Immutable snapshot of a Summary metric. */
010@StableApi
011public final class SummarySnapshot extends MetricSnapshot {
012
013  /**
014   * To create a new {@link SummarySnapshot}, you can either call the constructor directly or use
015   * the builder with {@link SummarySnapshot#builder()}.
016   *
017   * @param metadata See {@link MetricMetadata} for more naming conventions.
018   * @param data the constructor will create a sorted copy of the collection.
019   */
020  public SummarySnapshot(MetricMetadata metadata, Collection<SummaryDataPointSnapshot> data) {
021    this(metadata, data, false);
022  }
023
024  private SummarySnapshot(
025      MetricMetadata metadata, Collection<SummaryDataPointSnapshot> data, boolean internal) {
026    super(metadata, data, internal);
027  }
028
029  @SuppressWarnings("unchecked")
030  @Override
031  public List<SummaryDataPointSnapshot> getDataPoints() {
032    return (List<SummaryDataPointSnapshot>) dataPoints;
033  }
034
035  @SuppressWarnings("unchecked")
036  @Override
037  MetricSnapshot escape(
038      EscapingScheme escapingScheme, List<? extends DataPointSnapshot> dataPointSnapshots) {
039    return new SummarySnapshot(
040        getMetadata().escape(escapingScheme),
041        (List<SummarySnapshot.SummaryDataPointSnapshot>) dataPointSnapshots,
042        true);
043  }
044
045  public static final class SummaryDataPointSnapshot extends DistributionDataPointSnapshot {
046
047    private final Quantiles quantiles;
048
049    /**
050     * To create a new {@link SummaryDataPointSnapshot}, you can either call the constructor
051     * directly or use the Builder with {@link SummaryDataPointSnapshot#builder()}.
052     *
053     * @param count total number of observations. Optional, pass -1 if not available.
054     * @param sum sum of all observed values. Optional, pass {@link Double#NaN} if not available.
055     * @param quantiles must not be {@code null}. Use {@link Quantiles#EMPTY} if there are no
056     *     quantiles.
057     * @param labels must not be {@code null}. Use {@link Labels#EMPTY} if there are no labels.
058     * @param exemplars must not be {@code null}. Use {@link Exemplars#EMPTY} if there are no
059     *     exemplars.
060     * @param createdTimestampMillis timestamp (as in {@link System#currentTimeMillis()}) when this
061     *     summary data (this specific set of labels) was created. Note that this refers to the
062     *     creation of the timeseries, not the creation of the snapshot. The created timestamp
063     *     optional. Use {@code 0L} if there is no created timestamp.
064     */
065    public SummaryDataPointSnapshot(
066        long count,
067        double sum,
068        Quantiles quantiles,
069        Labels labels,
070        Exemplars exemplars,
071        long createdTimestampMillis) {
072      this(count, sum, quantiles, labels, exemplars, createdTimestampMillis, 0);
073    }
074
075    /**
076     * Constructor with an additional scrape timestamp. This is only useful in rare cases as the
077     * scrape timestamp is usually set by the Prometheus server during scraping. Exceptions include
078     * mirroring metrics with given timestamps from other metric sources.
079     */
080    public SummaryDataPointSnapshot(
081        long count,
082        double sum,
083        Quantiles quantiles,
084        Labels labels,
085        Exemplars exemplars,
086        long createdTimestampMillis,
087        long scrapeTimestampMillis) {
088      this(
089          count,
090          sum,
091          quantiles,
092          labels,
093          exemplars,
094          createdTimestampMillis,
095          scrapeTimestampMillis,
096          false);
097      validate();
098    }
099
100    private SummaryDataPointSnapshot(
101        long count,
102        double sum,
103        Quantiles quantiles,
104        Labels labels,
105        Exemplars exemplars,
106        long createdTimestampMillis,
107        long scrapeTimestampMillis,
108        boolean internal) {
109      super(count, sum, exemplars, labels, createdTimestampMillis, scrapeTimestampMillis, internal);
110      this.quantiles = quantiles;
111    }
112
113    public Quantiles getQuantiles() {
114      return quantiles;
115    }
116
117    private void validate() {
118      for (Label label : getLabels()) {
119        if (label.getName().equals("quantile")) {
120          throw new IllegalArgumentException("quantile is a reserved label name for summaries");
121        }
122      }
123      if (quantiles == null) {
124        throw new NullPointerException();
125      }
126    }
127
128    @Override
129    DataPointSnapshot escape(EscapingScheme escapingScheme) {
130      return new SummarySnapshot.SummaryDataPointSnapshot(
131          getCount(),
132          getSum(),
133          getQuantiles(),
134          SnapshotEscaper.escapeLabels(getLabels(), escapingScheme),
135          SnapshotEscaper.escapeExemplars(getExemplars(), escapingScheme),
136          getCreatedTimestampMillis(),
137          getScrapeTimestampMillis(),
138          true);
139    }
140
141    public static Builder builder() {
142      return new Builder();
143    }
144
145    public static class Builder extends DistributionDataPointSnapshot.Builder<Builder> {
146
147      private Quantiles quantiles = Quantiles.EMPTY;
148
149      private Builder() {}
150
151      @Override
152      protected Builder self() {
153        return this;
154      }
155
156      public Builder quantiles(Quantiles quantiles) {
157        this.quantiles = quantiles;
158        return this;
159      }
160
161      @Override
162      public Builder count(long count) {
163        super.count(count);
164        return this;
165      }
166
167      public SummaryDataPointSnapshot build() {
168        return new SummaryDataPointSnapshot(
169            count,
170            sum,
171            quantiles,
172            labels,
173            exemplars,
174            createdTimestampMillis,
175            scrapeTimestampMillis);
176      }
177    }
178  }
179
180  public static Builder builder() {
181    return new Builder();
182  }
183
184  public static class Builder extends MetricSnapshot.Builder<Builder> {
185
186    private final List<SummaryDataPointSnapshot> dataPoints = new ArrayList<>();
187
188    private Builder() {}
189
190    /** Add a data point. Call multiple times to add multiple data points. */
191    public Builder dataPoint(SummaryDataPointSnapshot data) {
192      dataPoints.add(data);
193      return this;
194    }
195
196    @Override
197    public SummarySnapshot build() {
198      return new SummarySnapshot(buildMetadata(), dataPoints);
199    }
200
201    @Override
202    protected Builder self() {
203      return this;
204    }
205  }
206}