001package io.prometheus.metrics.core.exemplars; 002 003import io.prometheus.metrics.annotations.StableApi; 004import io.prometheus.metrics.config.ExemplarsProperties; 005import io.prometheus.metrics.config.PrometheusProperties; 006import java.util.concurrent.TimeUnit; 007import javax.annotation.Nullable; 008 009@StableApi 010public class ExemplarSamplerConfig { 011 012 /** See {@link ExemplarsProperties#getMinRetentionPeriodSeconds()} */ 013 public static final int DEFAULT_MIN_RETENTION_PERIOD_SECONDS = 7; 014 015 /** See {@link ExemplarsProperties#getMaxRetentionPeriodSeconds()} */ 016 public static final int DEFAULT_MAX_RETENTION_PERIOD_SECONDS = 70; 017 018 /** See {@link ExemplarsProperties#getSampleIntervalMilliseconds()} */ 019 private static final int DEFAULT_SAMPLE_INTERVAL_MILLISECONDS = 90; 020 021 private final long minRetentionPeriodMillis; 022 private final long maxRetentionPeriodMillis; 023 private final long sampleIntervalMillis; 024 025 @Nullable 026 private final double[] histogramClassicUpperBounds; // null unless it's a classic histogram 027 028 // if histogramClassicUpperBounds != null, 029 // then numberOfExemplars == histogramClassicUpperBounds.length 030 private final int numberOfExemplars; 031 032 /** 033 * Constructor for all metric types except classic histograms. 034 * 035 * @param properties See {@link PrometheusProperties#getExemplarProperties()}. 036 * @param numberOfExemplars Counters have 1 Exemplar, native histograms and summaries have 4 037 * Exemplars by default. For classic histogram use {@link 038 * #ExemplarSamplerConfig(ExemplarsProperties, double[])}. 039 */ 040 public ExemplarSamplerConfig(ExemplarsProperties properties, int numberOfExemplars) { 041 this(properties, numberOfExemplars, null); 042 } 043 044 /** 045 * Constructor for classic histogram metrics. 046 * 047 * @param properties See {@link PrometheusProperties#getExemplarProperties()}. 048 * @param histogramClassicUpperBounds the ExemplarSampler will provide one Exemplar per histogram 049 * bucket. Must be sorted, and must include the +Inf bucket. 050 */ 051 public ExemplarSamplerConfig( 052 ExemplarsProperties properties, double[] histogramClassicUpperBounds) { 053 this(properties, histogramClassicUpperBounds.length, histogramClassicUpperBounds); 054 } 055 056 private ExemplarSamplerConfig( 057 ExemplarsProperties properties, 058 int numberOfExemplars, 059 @Nullable double[] histogramClassicUpperBounds) { 060 this( 061 TimeUnit.SECONDS.toMillis( 062 getOrDefault( 063 properties.getMinRetentionPeriodSeconds(), DEFAULT_MIN_RETENTION_PERIOD_SECONDS)), 064 TimeUnit.SECONDS.toMillis( 065 getOrDefault( 066 properties.getMaxRetentionPeriodSeconds(), DEFAULT_MAX_RETENTION_PERIOD_SECONDS)), 067 getOrDefault( 068 properties.getSampleIntervalMilliseconds(), DEFAULT_SAMPLE_INTERVAL_MILLISECONDS), 069 numberOfExemplars, 070 histogramClassicUpperBounds); 071 } 072 073 ExemplarSamplerConfig( 074 long minRetentionPeriodMillis, 075 long maxRetentionPeriodMillis, 076 long sampleIntervalMillis, 077 int numberOfExemplars, 078 @Nullable double[] histogramClassicUpperBounds) { 079 this.minRetentionPeriodMillis = minRetentionPeriodMillis; 080 this.maxRetentionPeriodMillis = maxRetentionPeriodMillis; 081 this.sampleIntervalMillis = sampleIntervalMillis; 082 this.numberOfExemplars = numberOfExemplars; 083 this.histogramClassicUpperBounds = histogramClassicUpperBounds; 084 validate(); 085 } 086 087 private void validate() { 088 if (minRetentionPeriodMillis <= 0) { 089 throw new IllegalArgumentException( 090 minRetentionPeriodMillis + ": minRetentionPeriod must be > 0."); 091 } 092 if (maxRetentionPeriodMillis <= 0) { 093 throw new IllegalArgumentException( 094 maxRetentionPeriodMillis + ": maxRetentionPeriod must be > 0."); 095 } 096 if (histogramClassicUpperBounds != null) { 097 if (histogramClassicUpperBounds.length == 0 098 || histogramClassicUpperBounds[histogramClassicUpperBounds.length - 1] 099 != Double.POSITIVE_INFINITY) { 100 throw new IllegalArgumentException( 101 "histogramClassicUpperBounds must contain the +Inf bucket."); 102 } 103 if (histogramClassicUpperBounds.length != numberOfExemplars) { 104 throw new IllegalArgumentException( 105 "histogramClassicUpperBounds.length must be equal to numberOfExemplars."); 106 } 107 double bound = histogramClassicUpperBounds[0]; 108 for (int i = 1; i < histogramClassicUpperBounds.length; i++) { 109 if (bound >= histogramClassicUpperBounds[i]) { 110 throw new IllegalArgumentException( 111 "histogramClassicUpperBounds must be sorted and must not contain duplicates."); 112 } 113 } 114 } 115 if (numberOfExemplars <= 0) { 116 throw new IllegalArgumentException(numberOfExemplars + ": numberOfExemplars must be > 0."); 117 } 118 } 119 120 private static <T> T getOrDefault(@Nullable T result, T defaultValue) { 121 return result != null ? result : defaultValue; 122 } 123 124 @Nullable 125 public double[] getHistogramClassicUpperBounds() { 126 return histogramClassicUpperBounds; 127 } 128 129 /** See {@link ExemplarsProperties#getMinRetentionPeriodSeconds()} */ 130 public long getMinRetentionPeriodMillis() { 131 return minRetentionPeriodMillis; 132 } 133 134 /** See {@link ExemplarsProperties#getMaxRetentionPeriodSeconds()} */ 135 public long getMaxRetentionPeriodMillis() { 136 return maxRetentionPeriodMillis; 137 } 138 139 /** See {@link ExemplarsProperties#getSampleIntervalMilliseconds()} */ 140 public long getSampleIntervalMillis() { 141 return sampleIntervalMillis; 142 } 143 144 /** 145 * Defaults: Counters have one Exemplar, native histograms and summaries have 4 Exemplars, classic 146 * histograms have one Exemplar per bucket. 147 */ 148 public int getNumberOfExemplars() { 149 return numberOfExemplars; 150 } 151}