Skip to content

Commit ae62f70

Browse files
committed
fix env var properties
Signed-off-by: Gregor Zeitlinger <gregor.zeitlinger@grafana.com>
1 parent de5cf18 commit ae62f70

File tree

3 files changed

+65
-21
lines changed

3 files changed

+65
-21
lines changed

prometheus-metrics-config/src/main/java/io/prometheus/metrics/config/PrometheusProperties.java

Lines changed: 49 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
package io.prometheus.metrics.config;
22

3+
import javax.annotation.Nullable;
34
import java.util.HashMap;
45
import java.util.Map;
5-
import javax.annotation.Nullable;
66

77
/**
88
* The Prometheus Java client library can be configured at runtime (e.g. using a properties file).
@@ -14,14 +14,51 @@ public class PrometheusProperties {
1414
private static final PrometheusProperties instance = PrometheusPropertiesLoader.load();
1515

1616
private final MetricsProperties defaultMetricsProperties;
17-
private final Map<String, MetricsProperties> metricProperties = new HashMap<>();
17+
private final MetricPropertiesMap metricProperties;
1818
private final ExemplarsProperties exemplarProperties;
1919
private final ExporterProperties exporterProperties;
2020
private final ExporterFilterProperties exporterFilterProperties;
2121
private final ExporterHttpServerProperties exporterHttpServerProperties;
2222
private final ExporterOpenTelemetryProperties exporterOpenTelemetryProperties;
2323
private final ExporterPushgatewayProperties exporterPushgatewayProperties;
2424

25+
/**
26+
* Map that stores metric-specific properties keyed by metric name in exposition format
27+
* (underscores instead of dots).
28+
*
29+
* <p>This wrapper makes it explicit that metric names are normalized to underscore format for
30+
* storage, matching how they appear in Prometheus exposition formats.
31+
*/
32+
static class MetricPropertiesMap {
33+
private final Map<String, MetricsProperties> map = new HashMap<>();
34+
35+
void putAll(Map<String, MetricsProperties> properties) {
36+
properties.forEach(this::put);
37+
}
38+
39+
void put(String metricName, MetricsProperties properties) {
40+
map.put(normalize(metricName), properties);
41+
}
42+
43+
/**
44+
* Get metric properties by metric name.
45+
*
46+
* <p>Accepts metric names in any format (with dots or underscores) and automatically converts
47+
* them to the normalized underscore format used for storage.
48+
*
49+
* @param metricName the metric name (dots will be converted to underscores)
50+
* @return the metric properties, or null if not configured
51+
*/
52+
@Nullable
53+
MetricsProperties get(String metricName) {
54+
return map.get(normalize(metricName));
55+
}
56+
57+
private static String normalize(String metricName) {
58+
return metricName.replace(".", "_");
59+
}
60+
}
61+
2562
/**
2663
* Get the properties instance. When called for the first time, {@code get()} loads the properties
2764
* from the following locations:
@@ -41,17 +78,18 @@ public static Builder builder() {
4178
return new Builder();
4279
}
4380

44-
public PrometheusProperties(
81+
// Package-private constructor for PrometheusPropertiesLoader and Builder
82+
PrometheusProperties(
4583
MetricsProperties defaultMetricsProperties,
46-
Map<String, MetricsProperties> metricProperties,
84+
MetricPropertiesMap metricProperties,
4785
ExemplarsProperties exemplarProperties,
4886
ExporterProperties exporterProperties,
4987
ExporterFilterProperties exporterFilterProperties,
5088
ExporterHttpServerProperties httpServerConfig,
5189
ExporterPushgatewayProperties pushgatewayProperties,
5290
ExporterOpenTelemetryProperties otelConfig) {
5391
this.defaultMetricsProperties = defaultMetricsProperties;
54-
this.metricProperties.putAll(metricProperties);
92+
this.metricProperties = metricProperties;
5593
this.exemplarProperties = exemplarProperties;
5694
this.exporterProperties = exporterProperties;
5795
this.exporterFilterProperties = exporterFilterProperties;
@@ -72,10 +110,13 @@ public MetricsProperties getDefaultMetricProperties() {
72110
* Properties specific for one metric. Should be merged with {@link
73111
* #getDefaultMetricProperties()}. May return {@code null} if no metric-specific properties are
74112
* configured for a metric name.
113+
*
114+
* @param metricName the metric name (dots will be automatically converted to underscores to match
115+
* exposition format)
75116
*/
76117
@Nullable
77118
public MetricsProperties getMetricProperties(String metricName) {
78-
return metricProperties.get(metricName.replace(".", "_"));
119+
return metricProperties.get(metricName);
79120
}
80121

81122
public ExemplarsProperties getExemplarProperties() {
@@ -104,7 +145,7 @@ public ExporterOpenTelemetryProperties getExporterOpenTelemetryProperties() {
104145

105146
public static class Builder {
106147
private MetricsProperties defaultMetricsProperties = MetricsProperties.builder().build();
107-
private Map<String, MetricsProperties> metricProperties = new HashMap<>();
148+
private final MetricPropertiesMap metricProperties = new MetricPropertiesMap();
108149
private ExemplarsProperties exemplarProperties = ExemplarsProperties.builder().build();
109150
private ExporterProperties exporterProperties = ExporterProperties.builder().build();
110151
private ExporterFilterProperties exporterFilterProperties =
@@ -124,7 +165,7 @@ public Builder defaultMetricsProperties(MetricsProperties defaultMetricsProperti
124165
}
125166

126167
public Builder metricProperties(Map<String, MetricsProperties> metricProperties) {
127-
this.metricProperties = metricProperties;
168+
this.metricProperties.putAll(metricProperties);
128169
return this;
129170
}
130171

prometheus-metrics-config/src/main/java/io/prometheus/metrics/config/PrometheusPropertiesLoader.java

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ public static PrometheusProperties load() throws PrometheusPropertiesException {
2727
public static PrometheusProperties load(Map<Object, Object> externalProperties)
2828
throws PrometheusPropertiesException {
2929
PropertySource propertySource = loadProperties(externalProperties);
30-
Map<String, MetricsProperties> metricsConfigs = loadMetricsConfigs(propertySource);
30+
PrometheusProperties.MetricPropertiesMap metricsConfigs = loadMetricsConfigs(propertySource);
3131
MetricsProperties defaultMetricsProperties =
3232
MetricsProperties.load("io.prometheus.metrics", propertySource);
3333
ExemplarsProperties exemplarConfig = ExemplarsProperties.load(propertySource);
@@ -53,8 +53,10 @@ public static PrometheusProperties load(Map<Object, Object> externalProperties)
5353
}
5454

5555
// This will remove entries from propertySource when they are processed.
56-
static Map<String, MetricsProperties> loadMetricsConfigs(PropertySource propertySource) {
57-
Map<String, MetricsProperties> result = new HashMap<>();
56+
static PrometheusProperties.MetricPropertiesMap loadMetricsConfigs(
57+
PropertySource propertySource) {
58+
PrometheusProperties.MetricPropertiesMap result =
59+
new PrometheusProperties.MetricPropertiesMap();
5860
// Note that the metric name in the properties file must be as exposed in the Prometheus
5961
// exposition formats,
6062
// i.e. all dots replaced with underscores.
@@ -89,7 +91,7 @@ static Map<String, MetricsProperties> loadMetricsConfigs(PropertySource property
8991
}
9092
}
9193

92-
if (metricName != null && !result.containsKey(metricName)) {
94+
if (metricName != null && result.get(metricName) == null) {
9395
result.put(
9496
metricName,
9597
MetricsProperties.load("io.prometheus.metrics." + metricName, propertySource));

prometheus-metrics-config/src/test/java/io/prometheus/metrics/config/PrometheusPropertiesLoaderTest.java

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
package io.prometheus.metrics.config;
22

3-
import static org.assertj.core.api.Assertions.assertThat;
4-
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
3+
import org.junit.jupiter.api.Test;
4+
import org.junitpioneer.jupiter.SetSystemProperty;
55

66
import java.util.HashMap;
77
import java.util.Map;
88
import java.util.Properties;
9-
import org.junit.jupiter.api.Test;
10-
import org.junitpioneer.jupiter.SetSystemProperty;
9+
10+
import static org.assertj.core.api.Assertions.assertThat;
11+
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
1112

1213
/** Tests for {@link PrometheusPropertiesLoader}. */
1314
class PrometheusPropertiesLoaderTest {
@@ -68,7 +69,7 @@ void environmentVariablesShouldConfigureMetrics() {
6869

6970
PropertySource propertySource =
7071
new PropertySource(new HashMap<>(), envVarProperties, new HashMap<>());
71-
Map<String, MetricsProperties> metricsConfigs =
72+
PrometheusProperties.MetricPropertiesMap metricsConfigs =
7273
PrometheusPropertiesLoader.loadMetricsConfigs(propertySource);
7374

7475
assertThat(metricsConfigs.get("http_duration_seconds").getHistogramClassicUpperBounds())
@@ -88,7 +89,7 @@ void environmentVariablesShouldHandleSnakeCaseMetricNames() {
8889

8990
PropertySource propertySource =
9091
new PropertySource(new HashMap<>(), envVarProperties, new HashMap<>());
91-
Map<String, MetricsProperties> metricsConfigs =
92+
PrometheusProperties.MetricPropertiesMap metricsConfigs =
9293
PrometheusPropertiesLoader.loadMetricsConfigs(propertySource);
9394

9495
assertThat(metricsConfigs.get("http_server").getHistogramNativeOnly()).isTrue();
@@ -102,7 +103,7 @@ void environmentVariablesShouldHandleMultipleSnakeCaseSegments() {
102103

103104
PropertySource propertySource =
104105
new PropertySource(new HashMap<>(), envVarProperties, new HashMap<>());
105-
Map<String, MetricsProperties> metricsConfigs =
106+
PrometheusProperties.MetricPropertiesMap metricsConfigs =
106107
PrometheusPropertiesLoader.loadMetricsConfigs(propertySource);
107108

108109
assertThat(metricsConfigs.get("my_custom_metric").getHistogramNativeOnly()).isTrue();
@@ -119,7 +120,7 @@ void environmentVariablesShouldHandleMetricNamesContainingPropertyKeywords() {
119120

120121
PropertySource propertySource =
121122
new PropertySource(new HashMap<>(), envVarProperties, new HashMap<>());
122-
Map<String, MetricsProperties> metricsConfigs =
123+
PrometheusProperties.MetricPropertiesMap metricsConfigs =
123124
PrometheusPropertiesLoader.loadMetricsConfigs(propertySource);
124125

125126
assertThat(metricsConfigs.get("my_summary_metric").getHistogramNativeOnly()).isTrue();
@@ -138,7 +139,7 @@ void regularPropertiesShouldHandleComplexMetricNames() {
138139
"io.prometheus.metrics.my_app_custom_metric.summary_quantiles", "0.5, 0.99");
139140

140141
PropertySource propertySource = new PropertySource(properties);
141-
Map<String, MetricsProperties> metricsConfigs =
142+
PrometheusProperties.MetricPropertiesMap metricsConfigs =
142143
PrometheusPropertiesLoader.loadMetricsConfigs(propertySource);
143144

144145
assertThat(metricsConfigs.get("http_server_requests_total").getHistogramNativeOnly()).isTrue();

0 commit comments

Comments
 (0)