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}