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