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        || includedNames.test(result.getMetadata().getExpositionBasePrometheusName())) {
039      return result;
040    } else {
041      return null;
042    }
043  }
044
045  /**
046   * Like {@link #collect(Predicate)}, but with support for multi-target pattern.
047   *
048   * <p>Override this if there is a more efficient way than first collecting the snapshot and then
049   * discarding it.
050   */
051  @Nullable
052  default MetricSnapshot collect(
053      Predicate<String> includedNames, PrometheusScrapeRequest scrapeRequest) {
054    MetricSnapshot result = collect(scrapeRequest);
055    if (includedNames.test(result.getMetadata().getPrometheusName())
056        || includedNames.test(result.getMetadata().getExpositionBasePrometheusName())) {
057      return result;
058    } else {
059      return null;
060    }
061  }
062
063  /**
064   * This is called in two places:
065   *
066   * <ol>
067   *   <li>During registration to check if a metric with that name already exists.
068   *   <li>During scrape to check if this collector can be skipped because a name filter is present
069   *       and the metric name is excluded.
070   * </ol>
071   *
072   * <p>Returning {@code null} means checks are omitted (registration the metric always succeeds),
073   * and the collector is always scraped (the result is dropped after scraping if a name filter is
074   * present and the metric name is excluded).
075   *
076   * <p>If your metric has a name that does not change at runtime it is a good idea to overwrite
077   * this and return the name.
078   *
079   * <p>All metrics in {@code prometheus-metrics-core} override this.
080   */
081  @Nullable
082  default String getPrometheusName() {
083    return null;
084  }
085
086  /**
087   * Returns the metric type for registration-time validation.
088   *
089   * <p>This is used to prevent different metric types (e.g., Counter and Gauge) from sharing the
090   * same name. Returning {@code null} means type validation is skipped for this collector.
091   *
092   * <p>Validation is performed only at registration time. If this method returns {@code null}, no
093   * type validation is performed for this collector, and duplicate or conflicting metrics may
094   * result in invalid exposition output.
095   *
096   * @return the metric type, or {@code null} to skip validation
097   */
098  @Nullable
099  default MetricType getMetricType() {
100    return null;
101  }
102
103  /**
104   * Returns the complete set of label names for this metric.
105   *
106   * <p>This includes both dynamic label names (specified in {@code labelNames()}) and constant
107   * label names (specified in {@code constLabels()}). Label names are normalized using Prometheus
108   * naming conventions.
109   *
110   * <p>This is used for registration-time validation to prevent duplicate label schemas for the
111   * same metric name. Two collectors with the same name and type can coexist if they have different
112   * label name sets.
113   *
114   * <p>Returning {@code null} is treated as an empty label set: the registry normalizes it to
115   * {@code Collections.emptySet()} and performs full label-schema validation and duplicate
116   * detection. Two collectors with the same name, type, and {@code null} (or empty) label names are
117   * considered duplicate and registration of the second will fail.
118   *
119   * @return the set of all label names, or {@code null} (treated as empty) for a metric with no
120   *     labels
121   */
122  @Nullable
123  default Set<String> getLabelNames() {
124    return null;
125  }
126
127  /**
128   * Returns the metric metadata (name, help, unit) for registration-time validation.
129   *
130   * <p>When non-null, the registry uses this to validate that metrics with the same name have
131   * consistent help and unit. Returning {@code null} means help/unit validation is skipped for this
132   * collector.
133   *
134   * @return the metric metadata, or {@code null} to skip help/unit validation
135   */
136  @Nullable
137  default MetricMetadata getMetadata() {
138    return null;
139  }
140}