001package io.prometheus.metrics.config; 002 003import java.util.HashMap; 004import java.util.Map; 005import javax.annotation.Nullable; 006 007/** 008 * The Prometheus Java client library can be configured at runtime (e.g. using a properties file). 009 * 010 * <p>This class represents the runtime configuration. 011 */ 012public class PrometheusProperties { 013 014 private static final PrometheusProperties instance = PrometheusPropertiesLoader.load(); 015 016 private final MetricsProperties defaultMetricsProperties; 017 private final MetricPropertiesMap metricProperties; 018 private final ExemplarsProperties exemplarProperties; 019 private final ExporterProperties exporterProperties; 020 private final ExporterFilterProperties exporterFilterProperties; 021 private final ExporterHttpServerProperties exporterHttpServerProperties; 022 private final ExporterOpenTelemetryProperties exporterOpenTelemetryProperties; 023 private final ExporterPushgatewayProperties exporterPushgatewayProperties; 024 025 /** 026 * Map that stores metric-specific properties keyed by metric name in exposition format 027 * (underscores instead of dots). 028 * 029 * <p>This wrapper makes it explicit that metric names are normalized to underscore format for 030 * storage, so that environment variables and properties with dots in metric names can be 031 * correctly looked up using normalized names. 032 */ 033 static class MetricPropertiesMap { 034 private final Map<String, MetricsProperties> map = new HashMap<>(); 035 036 void set(Map<String, MetricsProperties> properties) { 037 map.clear(); 038 properties.forEach(this::put); 039 } 040 041 void put(String metricName, MetricsProperties properties) { 042 map.put(normalize(metricName), properties); 043 } 044 045 /** 046 * Get metric properties by metric name. 047 * 048 * <p>Accepts metric names in any format (with dots or underscores) and automatically converts 049 * them to the normalized underscore format used for storage. 050 * 051 * @param metricName the metric name (dots will be converted to underscores) 052 * @return the metric properties, or null if not configured 053 */ 054 @Nullable 055 MetricsProperties get(String metricName) { 056 return map.get(normalize(metricName)); 057 } 058 059 // copied from PrometheusNaming - but we can't reuse that class here because it's in a module 060 // that 061 // depends on PrometheusProperties, which would create a circular dependency. 062 private static String normalize(String name) { 063 StringBuilder escaped = new StringBuilder(); 064 065 for (int i = 0; i < name.length(); ) { 066 int c = name.codePointAt(i); 067 if (isValidLegacyChar(c, i)) { 068 escaped.appendCodePoint(c); 069 } else { 070 escaped.append('_'); 071 } 072 i += Character.charCount(c); 073 } 074 return escaped.toString(); 075 } 076 } 077 078 private static boolean isValidLegacyChar(int c, int i) { 079 return (c >= 'a' && c <= 'z') 080 || (c >= 'A' && c <= 'Z') 081 || c == '_' 082 || c == ':' 083 || (c >= '0' && c <= '9' && i > 0); 084 } 085 086 /** 087 * Get the properties instance. When called for the first time, {@code get()} loads the properties 088 * from the following locations: 089 * 090 * <ul> 091 * <li>{@code prometheus.properties} file found in the classpath. 092 * <li>Properties file specified in the {@code PROMETHEUS_CONFIG} environment variable or the 093 * {@code prometheus.config} system property. 094 * <li>Individual properties from system properties. 095 * </ul> 096 */ 097 public static PrometheusProperties get() throws PrometheusPropertiesException { 098 return instance; 099 } 100 101 public static Builder builder() { 102 return new Builder(); 103 } 104 105 // Package-private constructor for PrometheusPropertiesLoader and Builder 106 PrometheusProperties( 107 MetricsProperties defaultMetricsProperties, 108 MetricPropertiesMap metricProperties, 109 ExemplarsProperties exemplarProperties, 110 ExporterProperties exporterProperties, 111 ExporterFilterProperties exporterFilterProperties, 112 ExporterHttpServerProperties httpServerConfig, 113 ExporterPushgatewayProperties pushgatewayProperties, 114 ExporterOpenTelemetryProperties otelConfig) { 115 this.defaultMetricsProperties = defaultMetricsProperties; 116 this.metricProperties = metricProperties; 117 this.exemplarProperties = exemplarProperties; 118 this.exporterProperties = exporterProperties; 119 this.exporterFilterProperties = exporterFilterProperties; 120 this.exporterHttpServerProperties = httpServerConfig; 121 this.exporterPushgatewayProperties = pushgatewayProperties; 122 this.exporterOpenTelemetryProperties = otelConfig; 123 } 124 125 /** 126 * The default metric properties apply for metrics where {@link #getMetricProperties(String)} is 127 * {@code null}. 128 */ 129 public MetricsProperties getDefaultMetricProperties() { 130 return defaultMetricsProperties; 131 } 132 133 /** 134 * Properties specific for one metric. Should be merged with {@link 135 * #getDefaultMetricProperties()}. May return {@code null} if no metric-specific properties are 136 * configured for a metric name. 137 * 138 * @param metricName the metric name (dots will be automatically converted to underscores to match 139 * exposition format) 140 */ 141 @Nullable 142 public MetricsProperties getMetricProperties(String metricName) { 143 return metricProperties.get(metricName); 144 } 145 146 public ExemplarsProperties getExemplarProperties() { 147 return exemplarProperties; 148 } 149 150 public ExporterProperties getExporterProperties() { 151 return exporterProperties; 152 } 153 154 public ExporterFilterProperties getExporterFilterProperties() { 155 return exporterFilterProperties; 156 } 157 158 public ExporterHttpServerProperties getExporterHttpServerProperties() { 159 return exporterHttpServerProperties; 160 } 161 162 public ExporterPushgatewayProperties getExporterPushgatewayProperties() { 163 return exporterPushgatewayProperties; 164 } 165 166 public ExporterOpenTelemetryProperties getExporterOpenTelemetryProperties() { 167 return exporterOpenTelemetryProperties; 168 } 169 170 public static class Builder { 171 private MetricsProperties defaultMetricsProperties = MetricsProperties.builder().build(); 172 private final MetricPropertiesMap metricProperties = new MetricPropertiesMap(); 173 private ExemplarsProperties exemplarProperties = ExemplarsProperties.builder().build(); 174 private ExporterProperties exporterProperties = ExporterProperties.builder().build(); 175 private ExporterFilterProperties exporterFilterProperties = 176 ExporterFilterProperties.builder().build(); 177 private ExporterHttpServerProperties exporterHttpServerProperties = 178 ExporterHttpServerProperties.builder().build(); 179 private ExporterPushgatewayProperties pushgatewayProperties = 180 ExporterPushgatewayProperties.builder().build(); 181 private ExporterOpenTelemetryProperties otelConfig = 182 ExporterOpenTelemetryProperties.builder().build(); 183 184 private Builder() {} 185 186 public Builder defaultMetricsProperties(MetricsProperties defaultMetricsProperties) { 187 this.defaultMetricsProperties = defaultMetricsProperties; 188 return this; 189 } 190 191 public Builder metricProperties(Map<String, MetricsProperties> metricProperties) { 192 this.metricProperties.set(metricProperties); 193 return this; 194 } 195 196 /** Convenience for adding a single named MetricsProperties */ 197 public Builder putMetricProperty(String name, MetricsProperties props) { 198 this.metricProperties.put(name, props); 199 return this; 200 } 201 202 public Builder exemplarProperties(ExemplarsProperties exemplarProperties) { 203 this.exemplarProperties = exemplarProperties; 204 return this; 205 } 206 207 public Builder exporterProperties(ExporterProperties exporterProperties) { 208 this.exporterProperties = exporterProperties; 209 return this; 210 } 211 212 public Builder exporterFilterProperties(ExporterFilterProperties exporterFilterProperties) { 213 this.exporterFilterProperties = exporterFilterProperties; 214 return this; 215 } 216 217 public Builder exporterHttpServerProperties( 218 ExporterHttpServerProperties exporterHttpServerProperties) { 219 this.exporterHttpServerProperties = exporterHttpServerProperties; 220 return this; 221 } 222 223 public Builder pushgatewayProperties(ExporterPushgatewayProperties pushgatewayProperties) { 224 this.pushgatewayProperties = pushgatewayProperties; 225 return this; 226 } 227 228 public Builder exporterOpenTelemetryProperties( 229 ExporterOpenTelemetryProperties exporterOpenTelemetryProperties) { 230 this.otelConfig = exporterOpenTelemetryProperties; 231 return this; 232 } 233 234 public PrometheusProperties build() { 235 return new PrometheusProperties( 236 defaultMetricsProperties, 237 metricProperties, 238 exemplarProperties, 239 exporterProperties, 240 exporterFilterProperties, 241 exporterHttpServerProperties, 242 pushgatewayProperties, 243 otelConfig); 244 } 245 } 246}