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