diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/export/otlp/OtlpMetricsProperties.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/export/otlp/OtlpMetricsProperties.java index bcda23c88c..983eff38a6 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/export/otlp/OtlpMetricsProperties.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/export/otlp/OtlpMetricsProperties.java @@ -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,7 +54,7 @@ public class OtlpMetricsProperties extends StepRegistryProperties { private Map 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; @@ -63,8 +64,8 @@ public class OtlpMetricsProperties extends StepRegistryProperties { 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; @@ -73,6 +74,11 @@ public class OtlpMetricsProperties extends StepRegistryProperties { */ private TimeUnit baseTimeUnit = TimeUnit.MILLISECONDS; + /** + * Per-meter properties that can be used to override defaults. + */ + private Map meter = new LinkedHashMap<>(); + public String getUrl() { return this.url; } @@ -129,4 +135,42 @@ public class OtlpMetricsProperties extends StepRegistryProperties { this.baseTimeUnit = baseTimeUnit; } + public Map getMeter() { + return this.meter; + } + + /** + * Per-meter settings. + */ + public static class Meter { + + /** + * Maximum number of buckets to be used for exponential histograms, if configured. + * This has no effect on explicit bucket histograms. + */ + private Integer maxBucketCount; + + /** + * Histogram type when histogram publishing is enabled. + */ + private HistogramFlavor histogramFlavor; + + public Integer getMaxBucketCount() { + return this.maxBucketCount; + } + + public void setMaxBucketCount(Integer maxBucketCount) { + this.maxBucketCount = maxBucketCount; + } + + public HistogramFlavor getHistogramFlavor() { + return this.histogramFlavor; + } + + public void setHistogramFlavor(HistogramFlavor histogramFlavor) { + this.histogramFlavor = histogramFlavor; + } + + } + } diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/export/otlp/OtlpMetricsPropertiesConfigAdapter.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/export/otlp/OtlpMetricsPropertiesConfigAdapter.java index 8ad4085583..d3f9c4838b 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/export/otlp/OtlpMetricsPropertiesConfigAdapter.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/export/otlp/OtlpMetricsPropertiesConfigAdapter.java @@ -20,15 +20,18 @@ import java.util.Collections; import java.util.LinkedHashMap; import java.util.Map; import java.util.concurrent.TimeUnit; +import java.util.function.Function; import io.micrometer.registry.otlp.AggregationTemporality; import io.micrometer.registry.otlp.HistogramFlavor; import io.micrometer.registry.otlp.OtlpConfig; +import org.springframework.boot.actuate.autoconfigure.metrics.export.otlp.OtlpMetricsProperties.Meter; import org.springframework.boot.actuate.autoconfigure.metrics.export.properties.StepRegistryPropertiesConfigAdapter; import org.springframework.boot.actuate.autoconfigure.opentelemetry.OpenTelemetryProperties; import org.springframework.boot.actuate.autoconfigure.opentelemetry.OpenTelemetryResourceAttributes; import org.springframework.core.env.Environment; +import org.springframework.util.CollectionUtils; /** * Adapter to convert {@link OtlpMetricsProperties} to an {@link OtlpConfig}. @@ -88,6 +91,16 @@ class OtlpMetricsPropertiesConfigAdapter extends StepRegistryPropertiesConfigAda return get(OtlpMetricsProperties::getHistogramFlavor, OtlpConfig.super::histogramFlavor); } + @Override + public Map histogramFlavorPerMeter() { + return get(perMeter(Meter::getHistogramFlavor), OtlpConfig.super::histogramFlavorPerMeter); + } + + @Override + public Map maxBucketsPerMeter() { + return get(perMeter(Meter::getMaxBucketCount), OtlpConfig.super::maxBucketsPerMeter); + } + @Override public int maxScale() { return get(OtlpMetricsProperties::getMaxScale, OtlpConfig.super::maxScale); @@ -103,4 +116,21 @@ class OtlpMetricsPropertiesConfigAdapter extends StepRegistryPropertiesConfigAda return get(OtlpMetricsProperties::getBaseTimeUnit, OtlpConfig.super::baseTimeUnit); } + private Function> perMeter(Function getter) { + return (properties) -> { + if (CollectionUtils.isEmpty(properties.getMeter())) { + return null; + } + Map perMeter = new LinkedHashMap<>(); + properties.getMeter().forEach((key, meterProperties) -> { + V value = getter.apply(meterProperties); + if (value != null) { + perMeter.put(key, value); + } + }); + return (!perMeter.isEmpty()) ? perMeter : null; + }; + + } + } diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/export/otlp/OtlpMetricsPropertiesConfigAdapterTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/export/otlp/OtlpMetricsPropertiesConfigAdapterTests.java index cd067216b1..7f050f1650 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/export/otlp/OtlpMetricsPropertiesConfigAdapterTests.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/export/otlp/OtlpMetricsPropertiesConfigAdapterTests.java @@ -25,6 +25,7 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.springframework.boot.actuate.autoconfigure.metrics.export.otlp.OtlpMetricsExportAutoConfiguration.PropertiesOtlpMetricsConnectionDetails; +import org.springframework.boot.actuate.autoconfigure.metrics.export.otlp.OtlpMetricsProperties.Meter; import org.springframework.boot.actuate.autoconfigure.opentelemetry.OpenTelemetryProperties; import org.springframework.mock.env.MockEnvironment; @@ -110,6 +111,20 @@ class OtlpMetricsPropertiesConfigAdapterTests { assertThat(createAdapter().histogramFlavor()).isSameAs(HistogramFlavor.BASE2_EXPONENTIAL_BUCKET_HISTOGRAM); } + @Test + void whenPropertiesHistogramFlavorPerMeterIsNotSetAdapterHistogramFlavorReturnsEmptyMap() { + assertThat(createAdapter().histogramFlavorPerMeter()).isEmpty(); + } + + @Test + void whenPropertiesHistogramFlavorPerMeterIsSetAdapterHistogramFlavorPerMeterReturnsIt() { + Meter meterProperties = new Meter(); + meterProperties.setHistogramFlavor(HistogramFlavor.BASE2_EXPONENTIAL_BUCKET_HISTOGRAM); + this.properties.getMeter().put("my.histograms", meterProperties); + assertThat(createAdapter().histogramFlavorPerMeter()).containsEntry("my.histograms", + HistogramFlavor.BASE2_EXPONENTIAL_BUCKET_HISTOGRAM); + } + @Test void whenPropertiesMaxScaleIsNotSetAdapterMaxScaleReturns20() { assertThat(createAdapter().maxScale()).isEqualTo(20); @@ -132,6 +147,19 @@ class OtlpMetricsPropertiesConfigAdapterTests { assertThat(createAdapter().maxBucketCount()).isEqualTo(6); } + @Test + void whenPropertiesMaxBucketsPerMeterIsNotSetAdapterMaxBucketsPerMeterReturnsEmptyMap() { + assertThat(createAdapter().maxBucketsPerMeter()).isEmpty(); + } + + @Test + void whenPropertiesMaxBucketsPerMeterIsSetAdapterMaxBucketsPerMeterReturnsIt() { + Meter meterProperties = new Meter(); + meterProperties.setMaxBucketCount(111); + this.properties.getMeter().put("my.histograms", meterProperties); + assertThat(createAdapter().maxBucketsPerMeter()).containsEntry("my.histograms", 111); + } + @Test void whenPropertiesBaseTimeUnitIsNotSetAdapterBaseTimeUnitReturnsMillis() { assertThat(createAdapter().baseTimeUnit()).isSameAs(TimeUnit.MILLISECONDS); diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/export/otlp/OtlpMetricsPropertiesTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/export/otlp/OtlpMetricsPropertiesTests.java index d4938491e7..2809e84a73 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/export/otlp/OtlpMetricsPropertiesTests.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/export/otlp/OtlpMetricsPropertiesTests.java @@ -40,6 +40,7 @@ class OtlpMetricsPropertiesTests extends StepRegistryPropertiesTests { assertThat(properties.getMaxScale()).isEqualTo(config.maxScale()); assertThat(properties.getMaxBucketCount()).isEqualTo(config.maxBucketCount()); assertThat(properties.getBaseTimeUnit()).isSameAs(config.baseTimeUnit()); + assertThat(properties.getMeter()).isEmpty(); } }