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