001package io.prometheus.metrics.model.snapshots;
002
003import io.prometheus.metrics.annotations.StableApi;
004import io.prometheus.metrics.model.registry.MetricType;
005import java.util.Collection;
006import java.util.Collections;
007import java.util.LinkedHashSet;
008import java.util.Set;
009import javax.annotation.Nullable;
010
011/** Registration-time descriptor for a metric family. */
012@StableApi
013public final class MetricFamilyDescriptor {
014
015  private final MetricType type;
016  private final MetricMetadata metadata;
017  private final Set<String> labelNames;
018
019  private MetricFamilyDescriptor(
020      MetricType type, MetricMetadata metadata, Collection<String> labelNames) {
021    if (type == null) {
022      throw new IllegalArgumentException("Missing required field: type is null");
023    }
024    if (metadata == null) {
025      throw new IllegalArgumentException("Missing required field: metadata is null");
026    }
027    if (labelNames == null) {
028      throw new IllegalArgumentException("Missing required field: labelNames is null");
029    }
030    this.type = type;
031    this.metadata = metadata;
032    this.labelNames = Collections.unmodifiableSet(new LinkedHashSet<>(labelNames));
033  }
034
035  public static MetricFamilyDescriptor of(MetricType type, MetricMetadata metadata) {
036    return of(type, metadata, Collections.emptySet());
037  }
038
039  public static MetricFamilyDescriptor of(
040      MetricType type, MetricMetadata metadata, Collection<String> labelNames) {
041    return new MetricFamilyDescriptor(type, metadata, labelNames);
042  }
043
044  public static Builder<?> of(MetricType type, String name) {
045    switch (type) {
046      case COUNTER:
047        return counter(name);
048      case GAUGE:
049        return gauge(name);
050      case HISTOGRAM:
051        return histogram(name);
052      case SUMMARY:
053        return summary(name);
054      case INFO:
055        return info(name);
056      case STATESET:
057        return stateSet(name);
058      case UNKNOWN:
059      default:
060        return unknown(name);
061    }
062  }
063
064  public static CounterBuilder counter(String name) {
065    return new CounterBuilder().name(name);
066  }
067
068  public static GaugeBuilder gauge(String name) {
069    return new GaugeBuilder().name(name);
070  }
071
072  public static HistogramBuilder histogram(String name) {
073    return new HistogramBuilder().name(name);
074  }
075
076  public static SummaryBuilder summary(String name) {
077    return new SummaryBuilder().name(name);
078  }
079
080  public static InfoBuilder info(String name) {
081    return new InfoBuilder().name(name);
082  }
083
084  public static StateSetBuilder stateSet(String name) {
085    return new StateSetBuilder().name(name);
086  }
087
088  public static UnknownBuilder unknown(String name) {
089    return new UnknownBuilder().name(name);
090  }
091
092  public MetricType getType() {
093    return type;
094  }
095
096  public MetricMetadata getMetadata() {
097    return metadata;
098  }
099
100  public Set<String> getLabelNames() {
101    return labelNames;
102  }
103
104  public String getPrometheusName() {
105    return metadata.getPrometheusName();
106  }
107
108  public abstract static class Builder<T extends Builder<T>> {
109
110    @Nullable protected String name;
111    @Nullable protected String help;
112    @Nullable protected Unit unit;
113    protected final Set<String> labelNames = new LinkedHashSet<>();
114
115    public T name(String name) {
116      this.name = name;
117      return self();
118    }
119
120    public T help(String help) {
121      if (help == null) {
122        throw new IllegalArgumentException("Missing required field: help is null");
123      }
124      this.help = help;
125      return self();
126    }
127
128    public T unit(Unit unit) {
129      if (unit == null) {
130        throw new IllegalArgumentException("Missing required field: unit is null");
131      }
132      this.unit = unit;
133      return self();
134    }
135
136    public T labelName(String labelName) {
137      this.labelNames.add(PrometheusNaming.prometheusName(labelName));
138      return self();
139    }
140
141    public T labelNames(String... labelNames) {
142      for (String labelName : labelNames) {
143        labelName(labelName);
144      }
145      return self();
146    }
147
148    public T labelNames(Collection<String> labelNames) {
149      for (String labelName : labelNames) {
150        labelName(labelName);
151      }
152      return self();
153    }
154
155    public MetricFamilyDescriptor build() {
156      return new MetricFamilyDescriptor(getType(), buildMetadata(), labelNames);
157    }
158
159    protected MetricMetadata buildMetadata() {
160      if (name == null) {
161        throw new IllegalArgumentException("Missing required field: name is null");
162      }
163      return MetricMetadataSupport.metricMetadata(name, help, unit);
164    }
165
166    protected abstract MetricType getType();
167
168    protected abstract T self();
169  }
170
171  public static final class CounterBuilder extends Builder<CounterBuilder> {
172
173    @Override
174    protected MetricMetadata buildMetadata() {
175      if (name == null) {
176        throw new IllegalArgumentException("Missing required field: name is null");
177      }
178      return MetricMetadataSupport.counterMetadata(name, help, unit);
179    }
180
181    @Override
182    protected MetricType getType() {
183      return MetricType.COUNTER;
184    }
185
186    @Override
187    protected CounterBuilder self() {
188      return this;
189    }
190  }
191
192  public static final class GaugeBuilder extends Builder<GaugeBuilder> {
193
194    @Override
195    protected MetricType getType() {
196      return MetricType.GAUGE;
197    }
198
199    @Override
200    protected GaugeBuilder self() {
201      return this;
202    }
203  }
204
205  public static final class HistogramBuilder extends Builder<HistogramBuilder> {
206
207    @Override
208    protected MetricType getType() {
209      return MetricType.HISTOGRAM;
210    }
211
212    @Override
213    protected HistogramBuilder self() {
214      return this;
215    }
216  }
217
218  public static final class SummaryBuilder extends Builder<SummaryBuilder> {
219
220    @Override
221    protected MetricType getType() {
222      return MetricType.SUMMARY;
223    }
224
225    @Override
226    protected SummaryBuilder self() {
227      return this;
228    }
229  }
230
231  public static final class InfoBuilder extends Builder<InfoBuilder> {
232
233    @Override
234    public InfoBuilder unit(Unit unit) {
235      if (unit == null) {
236        throw new IllegalArgumentException("Missing required field: unit is null");
237      }
238      throw new IllegalArgumentException("Info metric cannot have a unit.");
239    }
240
241    @Override
242    protected MetricMetadata buildMetadata() {
243      if (name == null) {
244        throw new IllegalArgumentException("Missing required field: name is null");
245      }
246      return MetricMetadataSupport.infoMetadata(name, help);
247    }
248
249    @Override
250    protected MetricType getType() {
251      return MetricType.INFO;
252    }
253
254    @Override
255    protected InfoBuilder self() {
256      return this;
257    }
258  }
259
260  public static final class StateSetBuilder extends Builder<StateSetBuilder> {
261
262    @Override
263    public StateSetBuilder unit(Unit unit) {
264      if (unit == null) {
265        throw new IllegalArgumentException("Missing required field: unit is null");
266      }
267      throw new IllegalArgumentException("State set metric cannot have a unit.");
268    }
269
270    @Override
271    protected MetricType getType() {
272      return MetricType.STATESET;
273    }
274
275    @Override
276    protected StateSetBuilder self() {
277      return this;
278    }
279  }
280
281  public static final class UnknownBuilder extends Builder<UnknownBuilder> {
282
283    @Override
284    protected MetricType getType() {
285      return MetricType.UNKNOWN;
286    }
287
288    @Override
289    protected UnknownBuilder self() {
290      return this;
291    }
292  }
293}