Support Per-meter configuration for OtlpMetricsProperties

Add configuration properties support for the new `OtlpConfig` methods
`histogramFlavorPerMeter` and `maxBucketsPerMeter`. The existing
`histogramFlavor` and `maxBucketCount` configuration properties are
used as defaults when there isn't a specific per-meter configuration
set.

See gh-45203
This commit is contained in:
Tommy Ludwig
2025-04-09 16:27:32 +09:00
committed by Phillip Webb
parent 8f8a05264b
commit 6dfc8f9567
5 changed files with 68 additions and 4 deletions

View File

@@ -16,6 +16,7 @@
package org.springframework.boot.actuate.autoconfigure.metrics.export.otlp;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;
@@ -53,21 +54,32 @@ public class OtlpMetricsProperties extends StepRegistryProperties {
private Map<String, String> headers;
/**
* Histogram type to be preferred when histogram publishing is enabled.
* Default histogram type when histogram publishing is enabled.
*/
private HistogramFlavor histogramFlavor = HistogramFlavor.EXPLICIT_BUCKET_HISTOGRAM;
/**
* Per meter histogram type to be preferred when histogram publishing is enabled.
*/
private Map<String, HistogramFlavor> histogramFlavorPerMeter = new LinkedHashMap<>();
/**
* Max scale to use for exponential histograms, if configured.
*/
private int maxScale = 20;
/**
* Maximum number of buckets to be used for exponential histograms, if configured.
* This has no effect on explicit bucket histograms.
* Default maximum number of buckets to be used for exponential histograms, if
* configured. This has no effect on explicit bucket histograms.
*/
private int maxBucketCount = 160;
/**
* Per meter number of max buckets used for exponential histograms, if configured.
* This has no effect on explicit bucket histograms.
*/
private Map<String, Integer> maxBucketsPerMeter = new LinkedHashMap<>();
/**
* Time unit for exported metrics.
*/
@@ -105,6 +117,14 @@ public class OtlpMetricsProperties extends StepRegistryProperties {
this.histogramFlavor = histogramFlavor;
}
public Map<String, HistogramFlavor> getHistogramFlavorPerMeter() {
return this.histogramFlavorPerMeter;
}
public void setHistogramFlavorPerMeter(Map<String, HistogramFlavor> histogramFlavorPerMeter) {
this.histogramFlavorPerMeter = histogramFlavorPerMeter;
}
public int getMaxScale() {
return this.maxScale;
}
@@ -121,6 +141,14 @@ public class OtlpMetricsProperties extends StepRegistryProperties {
this.maxBucketCount = maxBucketCount;
}
public Map<String, Integer> getMaxBucketsPerMeter() {
return this.maxBucketsPerMeter;
}
public void setMaxBucketsPerMeter(Map<String, Integer> maxBucketsPerMeter) {
this.maxBucketsPerMeter = maxBucketsPerMeter;
}
public TimeUnit getBaseTimeUnit() {
return this.baseTimeUnit;
}

View File

@@ -88,6 +88,16 @@ class OtlpMetricsPropertiesConfigAdapter extends StepRegistryPropertiesConfigAda
return get(OtlpMetricsProperties::getHistogramFlavor, OtlpConfig.super::histogramFlavor);
}
@Override
public Map<String, HistogramFlavor> histogramFlavorPerMeter() {
return get(OtlpMetricsProperties::getHistogramFlavorPerMeter, OtlpConfig.super::histogramFlavorPerMeter);
}
@Override
public Map<String, Integer> maxBucketsPerMeter() {
return get(OtlpMetricsProperties::getMaxBucketsPerMeter, OtlpConfig.super::maxBucketsPerMeter);
}
@Override
public int maxScale() {
return get(OtlpMetricsProperties::getMaxScale, OtlpConfig.super::maxScale);

View File

@@ -110,6 +110,19 @@ class OtlpMetricsPropertiesConfigAdapterTests {
assertThat(createAdapter().histogramFlavor()).isSameAs(HistogramFlavor.BASE2_EXPONENTIAL_BUCKET_HISTOGRAM);
}
@Test
void whenPropertiesHistogramFlavorPerMeterIsNotSetAdapterHistogramFlavorReturnsEmptyMap() {
assertThat(createAdapter().histogramFlavorPerMeter()).isEmpty();
}
@Test
void whenPropertiesHistogramFlavorPerMeterIsSetAdapterHistogramFlavorPerMeterReturnsIt() {
this.properties
.setHistogramFlavorPerMeter(Map.of("my.histograms", HistogramFlavor.BASE2_EXPONENTIAL_BUCKET_HISTOGRAM));
assertThat(createAdapter().histogramFlavorPerMeter()).containsEntry("my.histograms",
HistogramFlavor.BASE2_EXPONENTIAL_BUCKET_HISTOGRAM);
}
@Test
void whenPropertiesMaxScaleIsNotSetAdapterMaxScaleReturns20() {
assertThat(createAdapter().maxScale()).isEqualTo(20);
@@ -132,6 +145,17 @@ class OtlpMetricsPropertiesConfigAdapterTests {
assertThat(createAdapter().maxBucketCount()).isEqualTo(6);
}
@Test
void whenPropertiesMaxBucketsPerMeterIsNotSetAdapterMaxBucketsPerMeterReturnsEmptyMap() {
assertThat(createAdapter().maxBucketsPerMeter()).isEmpty();
}
@Test
void whenPropertiesMaxBucketsPerMeterIsSetAdapterMaxBucketsPerMeterReturnsIt() {
this.properties.setMaxBucketsPerMeter(Map.of("my.histograms", 111));
assertThat(createAdapter().maxBucketsPerMeter()).containsEntry("my.histograms", 111);
}
@Test
void whenPropertiesBaseTimeUnitIsNotSetAdapterBaseTimeUnitReturnsMillis() {
assertThat(createAdapter().baseTimeUnit()).isSameAs(TimeUnit.MILLISECONDS);

View File

@@ -37,8 +37,10 @@ class OtlpMetricsPropertiesTests extends StepRegistryPropertiesTests {
assertStepRegistryDefaultValues(properties, config);
assertThat(properties.getAggregationTemporality()).isSameAs(config.aggregationTemporality());
assertThat(properties.getHistogramFlavor()).isSameAs(config.histogramFlavor());
assertThat(properties.getHistogramFlavorPerMeter()).isEqualTo(config.histogramFlavorPerMeter());
assertThat(properties.getMaxScale()).isEqualTo(config.maxScale());
assertThat(properties.getMaxBucketCount()).isEqualTo(config.maxBucketCount());
assertThat(properties.getMaxBucketsPerMeter()).isEqualTo(config.maxBucketsPerMeter());
assertThat(properties.getBaseTimeUnit()).isSameAs(config.baseTimeUnit());
}

View File

@@ -1548,7 +1548,7 @@ bom {
releaseNotes("https://github.com/apache/maven-war-plugin/releases/tag/maven-war-plugin-{version}")
}
}
library("Micrometer", "1.15.0-SNAPSHOT") {
library("Micrometer", "1.15.0-RC1") {
considerSnapshots()
group("io.micrometer") {
modules = [