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 io.prometheus.metrics.model.snapshots.MetricSnapshots; 008import java.util.ArrayList; 009import java.util.Collections; 010import java.util.List; 011import java.util.Set; 012import java.util.function.Predicate; 013import javax.annotation.Nullable; 014 015/** Like {@link Collector}, but collecting multiple Snapshots at once. */ 016@FunctionalInterface 017@StableApi 018public interface MultiCollector { 019 020 /** Called when the Prometheus server scrapes metrics. */ 021 MetricSnapshots 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 MetricSnapshots collect(PrometheusScrapeRequest scrapeRequest) { 028 return collect(); 029 } 030 031 /** 032 * Like {@link #collect()}, but returns only the snapshots where {@code includedNames.test(name)} 033 * is {@code true}. 034 * 035 * <p>Override this if there is a more efficient way than first collecting all snapshot and then 036 * discarding the excluded ones. 037 */ 038 default MetricSnapshots collect(Predicate<String> includedNames) { 039 return collect(includedNames, null); 040 } 041 042 /** 043 * Like {@link #collect(Predicate)}, but with support for multi-target pattern. 044 * 045 * <p>Override this if there is a more efficient way than first collecting the snapshot and then 046 * discarding it. 047 */ 048 default MetricSnapshots collect( 049 Predicate<String> includedNames, @Nullable PrometheusScrapeRequest scrapeRequest) { 050 MetricSnapshots allSnapshots = scrapeRequest == null ? collect() : collect(scrapeRequest); 051 MetricSnapshots.Builder result = MetricSnapshots.builder(); 052 for (MetricSnapshot snapshot : allSnapshots) { 053 if (includedNames.test(snapshot.getMetadata().getPrometheusName())) { 054 result.metricSnapshot(snapshot); 055 } 056 } 057 return result.build(); 058 } 059 060 /** 061 * Returns registration-time descriptors for the metric families collected by this collector. 062 * 063 * <p>The registry uses these descriptors for duplicate-name, type, label-schema, help, and unit 064 * validation at registration time. Returning an empty list means registration-time validation is 065 * skipped for this collector. 066 * 067 * <p>The default implementation adapts the deprecated fragmented metadata methods. New collectors 068 * with fixed registration-time metadata should override this method directly. 069 */ 070 @SuppressWarnings("deprecation") 071 default List<MetricFamilyDescriptor> getMetricFamilyDescriptors() { 072 List<String> prometheusNames = getPrometheusNames(); 073 List<MetricFamilyDescriptor> descriptors = new ArrayList<>(prometheusNames.size()); 074 for (String prometheusName : prometheusNames) { 075 MetricType metricType = getMetricType(prometheusName); 076 if (metricType != null) { 077 MetricMetadata metadata = getMetadata(prometheusName); 078 if (metadata == null) { 079 metadata = new MetricMetadata(prometheusName); 080 } 081 Set<String> labelNames = getLabelNames(prometheusName); 082 descriptors.add( 083 MetricFamilyDescriptor.of( 084 metricType, metadata, labelNames == null ? Collections.emptySet() : labelNames)); 085 } 086 } 087 return Collections.unmodifiableList(descriptors); 088 } 089 090 /** 091 * This is called in two places: 092 * 093 * <ol> 094 * <li>During registration to check if a metric with that name already exists. 095 * <li>During scrape to check if the collector can be skipped because a name filter is present 096 * and all names are excluded. 097 * </ol> 098 * 099 * <p>Returning an empty list means checks are omitted (registration metric always succeeds), and 100 * the collector is always scraped (if a name filter is present and all names are excluded the 101 * result is dropped). 102 * 103 * <p>If your collector returns a constant list of metrics that have names that do not change at 104 * runtime it is a good idea to overwrite this and return the names. 105 * 106 * @deprecated Override {@link #getMetricFamilyDescriptors()} instead. 107 */ 108 @Deprecated 109 default List<String> getPrometheusNames() { 110 return Collections.emptyList(); 111 } 112 113 /** 114 * Returns the metric type for the given Prometheus name. 115 * 116 * <p>This is used for per-name type validation during registration. Returning {@code null} means 117 * type validation is skipped for that specific metric name. 118 * 119 * <p>Validation is performed only at registration time. If this method returns {@code null}, no 120 * type validation is performed for that name, and duplicate or conflicting metrics may result in 121 * invalid exposition output. 122 * 123 * @param prometheusName the Prometheus metric name 124 * @return the metric type for the given name, or {@code null} to skip validation 125 * @deprecated Override {@link #getMetricFamilyDescriptors()} instead. 126 */ 127 @Deprecated 128 @Nullable 129 default MetricType getMetricType(String prometheusName) { 130 return null; 131 } 132 133 /** 134 * Returns the complete set of label names for the given Prometheus name. 135 * 136 * <p>This includes both dynamic label names and constant label names. Label names are normalized 137 * using Prometheus naming conventions (dots converted to underscores). 138 * 139 * <p>This is used for per-name label schema validation during registration. Two collectors with 140 * the same name and type can coexist if they have different label name sets. 141 * 142 * <p>Returning {@code null} is treated as an empty label set: the registry normalizes it to 143 * {@code Collections.emptySet()} and performs full label-schema validation and duplicate 144 * detection. Two collectors with the same name, type, and {@code null} (or empty) label names are 145 * considered duplicate and registration of the second will fail. 146 * 147 * @param prometheusName the Prometheus metric name 148 * @return the set of all label names for the given name, or {@code null} (treated as empty) for a 149 * metric with no labels 150 * @deprecated Override {@link #getMetricFamilyDescriptors()} instead. 151 */ 152 @Deprecated 153 @Nullable 154 default Set<String> getLabelNames(String prometheusName) { 155 return null; 156 } 157 158 /** 159 * Returns the metric metadata (name, help, unit) for the given Prometheus name. 160 * 161 * <p>When non-null, the registry uses this to validate that metrics with the same name have 162 * consistent help and unit. Returning {@code null} means help/unit validation is skipped for that 163 * name. 164 * 165 * @param prometheusName the Prometheus metric name 166 * @return the metric metadata for that name, or {@code null} to skip help/unit validation 167 * @deprecated Override {@link #getMetricFamilyDescriptors()} instead. 168 */ 169 @Deprecated 170 @Nullable 171 default MetricMetadata getMetadata(String prometheusName) { 172 return null; 173 } 174}