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