001package io.prometheus.metrics.model.registry;
002
003import io.prometheus.metrics.model.snapshots.MetricMetadata;
004import io.prometheus.metrics.model.snapshots.MetricSnapshot;
005import io.prometheus.metrics.model.snapshots.MetricSnapshots;
006import java.util.Collections;
007import java.util.List;
008import java.util.Set;
009import java.util.function.Predicate;
010import javax.annotation.Nullable;
011
012/** Like {@link Collector}, but collecting multiple Snapshots at once. */
013@FunctionalInterface
014public interface MultiCollector {
015
016  /** Called when the Prometheus server scrapes metrics. */
017  MetricSnapshots 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 MetricSnapshots collect(PrometheusScrapeRequest scrapeRequest) {
024    return collect();
025  }
026
027  /**
028   * Like {@link #collect()}, but returns only the snapshots where {@code includedNames.test(name)}
029   * is {@code true}.
030   *
031   * <p>Override this if there is a more efficient way than first collecting all snapshot and then
032   * discarding the excluded ones.
033   */
034  default MetricSnapshots collect(Predicate<String> includedNames) {
035    return collect(includedNames, null);
036  }
037
038  /**
039   * Like {@link #collect(Predicate)}, but with support for multi-target pattern.
040   *
041   * <p>Override this if there is a more efficient way than first collecting the snapshot and then
042   * discarding it.
043   */
044  default MetricSnapshots collect(
045      Predicate<String> includedNames, @Nullable PrometheusScrapeRequest scrapeRequest) {
046    MetricSnapshots allSnapshots = scrapeRequest == null ? collect() : collect(scrapeRequest);
047    MetricSnapshots.Builder result = MetricSnapshots.builder();
048    for (MetricSnapshot snapshot : allSnapshots) {
049      if (includedNames.test(snapshot.getMetadata().getPrometheusName())) {
050        result.metricSnapshot(snapshot);
051      }
052    }
053    return result.build();
054  }
055
056  /**
057   * This is called in two places:
058   *
059   * <ol>
060   *   <li>During registration to check if a metric with that name already exists.
061   *   <li>During scrape to check if the collector can be skipped because a name filter is present
062   *       and all names are excluded.
063   * </ol>
064   *
065   * <p>Returning an empty list means checks are omitted (registration metric always succeeds), and
066   * the collector is always scraped (if a name filter is present and all names are excluded the
067   * result is dropped).
068   *
069   * <p>If your collector returns a constant list of metrics that have names that do not change at
070   * runtime it is a good idea to overwrite this and return the names.
071   */
072  default List<String> getPrometheusNames() {
073    return Collections.emptyList();
074  }
075
076  /**
077   * Returns the metric type for the given Prometheus name.
078   *
079   * <p>This is used for per-name type validation during registration. Returning {@code null} means
080   * type validation is skipped for that specific metric name.
081   *
082   * <p>Validation is performed only at registration time. If this method returns {@code null}, no
083   * type validation is performed for that name, and duplicate or conflicting metrics may result in
084   * invalid exposition output.
085   *
086   * @param prometheusName the Prometheus metric name
087   * @return the metric type for the given name, or {@code null} to skip validation
088   */
089  @Nullable
090  default MetricType getMetricType(String prometheusName) {
091    return null;
092  }
093
094  /**
095   * Returns the complete set of label names for the given Prometheus name.
096   *
097   * <p>This includes both dynamic label names and constant label names. Label names are normalized
098   * using Prometheus naming conventions (dots converted to underscores).
099   *
100   * <p>This is used for per-name label schema validation during registration. Two collectors with
101   * the same name and type can coexist if they have different label name sets.
102   *
103   * <p>Returning {@code null} is treated as an empty label set: the registry normalizes it to
104   * {@code Collections.emptySet()} and performs full label-schema validation and duplicate
105   * detection. Two collectors with the same name, type, and {@code null} (or empty) label names are
106   * considered duplicate and registration of the second will fail.
107   *
108   * @param prometheusName the Prometheus metric name
109   * @return the set of all label names for the given name, or {@code null} (treated as empty) for a
110   *     metric with no labels
111   */
112  @Nullable
113  default Set<String> getLabelNames(String prometheusName) {
114    return null;
115  }
116
117  /**
118   * Returns the metric metadata (name, help, unit) for the given Prometheus name.
119   *
120   * <p>When non-null, the registry uses this to validate that metrics with the same name have
121   * consistent help and unit. Returning {@code null} means help/unit validation is skipped for that
122   * name.
123   *
124   * @param prometheusName the Prometheus metric name
125   * @return the metric metadata for that name, or {@code null} to skip help/unit validation
126   */
127  @Nullable
128  default MetricMetadata getMetadata(String prometheusName) {
129    return null;
130  }
131}