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