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}