001package io.prometheus.metrics.model.registry;
002
003import io.prometheus.metrics.model.snapshots.MetricMetadata;
004import io.prometheus.metrics.model.snapshots.MetricSnapshot;
005import java.util.Set;
006import java.util.function.Predicate;
007import javax.annotation.Nullable;
008
009/**
010 * To be registered with the Prometheus collector registry. See <i>Overall Structure</i> on <a
011 * href="https://prometheus.io/docs/instrumenting/writing_clientlibs/">https://prometheus.io/docs/instrumenting/writing_clientlibs/</a>.
012 */
013@FunctionalInterface
014public interface Collector {
015
016  /** Called when the Prometheus server scrapes metrics. */
017  MetricSnapshot collect();
018
019  /**
020   * Provides Collector with the details of the request issued by Prometheus to allow multi-target
021   * pattern implementation Override to implement request dependent logic to provide MetricSnapshot
022   */
023  default MetricSnapshot collect(PrometheusScrapeRequest scrapeRequest) {
024    return collect();
025  }
026
027  /**
028   * Like {@link #collect()}, but returns {@code null} if {@code includedNames.test(name)} is {@code
029   * false}.
030   *
031   * <p>Override this if there is a more efficient way than first collecting the snapshot and then
032   * discarding it.
033   */
034  @Nullable
035  default MetricSnapshot collect(Predicate<String> includedNames) {
036    MetricSnapshot result = collect();
037    if (includedNames.test(result.getMetadata().getPrometheusName())) {
038      return result;
039    } else {
040      return null;
041    }
042  }
043
044  /**
045   * Like {@link #collect(Predicate)}, but with support for multi-target pattern.
046   *
047   * <p>Override this if there is a more efficient way than first collecting the snapshot and then
048   * discarding it.
049   */
050  @Nullable
051  default MetricSnapshot collect(
052      Predicate<String> includedNames, PrometheusScrapeRequest scrapeRequest) {
053    MetricSnapshot result = collect(scrapeRequest);
054    if (includedNames.test(result.getMetadata().getPrometheusName())) {
055      return result;
056    } else {
057      return null;
058    }
059  }
060
061  /**
062   * This is called in two places:
063   *
064   * <ol>
065   *   <li>During registration to check if a metric with that name already exists.
066   *   <li>During scrape to check if this collector can be skipped because a name filter is present
067   *       and the metric name is excluded.
068   * </ol>
069   *
070   * <p>Returning {@code null} means checks are omitted (registration the metric always succeeds),
071   * and the collector is always scraped (the result is dropped after scraping if a name filter is
072   * present and the metric name is excluded).
073   *
074   * <p>If your metric has a name that does not change at runtime it is a good idea to overwrite
075   * this and return the name.
076   *
077   * <p>All metrics in {@code prometheus-metrics-core} override this.
078   */
079  @Nullable
080  default String getPrometheusName() {
081    return null;
082  }
083
084  /**
085   * Returns the metric type for registration-time validation.
086   *
087   * <p>This is used to prevent different metric types (e.g., Counter and Gauge) from sharing the
088   * same name. Returning {@code null} means type validation is skipped for this collector.
089   *
090   * <p>Validation is performed only at registration time. If this method returns {@code null}, no
091   * type validation is performed for this collector, and duplicate or conflicting metrics may
092   * result in invalid exposition output.
093   *
094   * @return the metric type, or {@code null} to skip validation
095   */
096  @Nullable
097  default MetricType getMetricType() {
098    return null;
099  }
100
101  /**
102   * Returns the complete set of label names for this metric.
103   *
104   * <p>This includes both dynamic label names (specified in {@code labelNames()}) and constant
105   * label names (specified in {@code constLabels()}). Label names are normalized using Prometheus
106   * naming conventions.
107   *
108   * <p>This is used for registration-time validation to prevent duplicate label schemas for the
109   * same metric name. Two collectors with the same name and type can coexist if they have different
110   * label name sets.
111   *
112   * <p>Returning {@code null} is treated as an empty label set: the registry normalizes it to
113   * {@code Collections.emptySet()} and performs full label-schema validation and duplicate
114   * detection. Two collectors with the same name, type, and {@code null} (or empty) label names are
115   * considered duplicate and registration of the second will fail.
116   *
117   * @return the set of all label names, or {@code null} (treated as empty) for a metric with no
118   *     labels
119   */
120  @Nullable
121  default Set<String> getLabelNames() {
122    return null;
123  }
124
125  /**
126   * Returns the metric metadata (name, help, unit) for registration-time validation.
127   *
128   * <p>When non-null, the registry uses this to validate that metrics with the same name have
129   * consistent help and unit. Returning {@code null} means help/unit validation is skipped for this
130   * collector.
131   *
132   * @return the metric metadata, or {@code null} to skip help/unit validation
133   */
134  @Nullable
135  default MetricMetadata getMetadata() {
136    return null;
137  }
138}