001package io.prometheus.metrics.core.metrics;
002
003import io.prometheus.metrics.annotations.StableApi;
004import io.prometheus.metrics.config.PrometheusProperties;
005import io.prometheus.metrics.model.registry.Collector;
006import io.prometheus.metrics.model.registry.PrometheusRegistry;
007import io.prometheus.metrics.model.snapshots.Label;
008import io.prometheus.metrics.model.snapshots.Labels;
009import io.prometheus.metrics.model.snapshots.MetricSnapshot;
010import java.util.ArrayList;
011import java.util.List;
012
013/** Common base class for all metrics. */
014@StableApi
015public abstract class Metric implements Collector {
016
017  protected final Labels constLabels;
018
019  protected Metric(Builder<?, ?> builder) {
020    this.constLabels = builder.constLabels;
021  }
022
023  @Override
024  public abstract MetricSnapshot collect();
025
026  protected abstract static class Builder<B extends Builder<B, M>, M extends Metric> {
027
028    protected final List<String> illegalLabelNames;
029    protected final PrometheusProperties properties;
030    protected Labels constLabels = Labels.EMPTY;
031
032    protected Builder(List<String> illegalLabelNames, PrometheusProperties properties) {
033      this.illegalLabelNames = new ArrayList<>(illegalLabelNames);
034      this.properties = properties;
035    }
036
037    // ConstLabels are only used rarely. In particular, do not use them to
038    // attach the same labels to all your metrics. Those use cases are
039    // better covered by target labels set by the scraping Prometheus
040    // server, or by one specific metric (e.g. a build_info or a
041    // machine_role metric). See also
042    // https://prometheus.io/docs/instrumenting/writing_exporters/#target-labels-not-static-scraped-labels
043    public B constLabels(Labels constLabels) {
044      for (Label label : constLabels) { // NPE if constLabels is null
045        if (illegalLabelNames.contains(label.getName())) {
046          throw new IllegalArgumentException(
047              label.getName() + ": illegal label name for this metric type");
048        }
049      }
050      this.constLabels = constLabels;
051      return self();
052    }
053
054    public M register() {
055      return register(PrometheusRegistry.defaultRegistry);
056    }
057
058    public M register(PrometheusRegistry registry) {
059      M metric = build();
060      registry.register(metric);
061      return metric;
062    }
063
064    public abstract M build();
065
066    protected abstract B self();
067  }
068}