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