From b60cfe9360854cdd7b781bf4ae8aea66944e556d Mon Sep 17 00:00:00 2001 From: Phillip Webb Date: Tue, 15 Apr 2025 11:35:55 -0700 Subject: [PATCH] Polish 'Support Per-meter configuration for OtlpMetricsProperties' See gh-45203 --- .../export/otlp/OtlpMetricsProperties.java | 68 ++++++++++++------- .../OtlpMetricsPropertiesConfigAdapter.java | 24 ++++++- ...lpMetricsPropertiesConfigAdapterTests.java | 10 ++- .../otlp/OtlpMetricsPropertiesTests.java | 3 +- .../spring-boot-dependencies/build.gradle | 2 +- 5 files changed, 73 insertions(+), 34 deletions(-) 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 139ff2fd353..983eff38a69 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 @@ -58,11 +58,6 @@ public class OtlpMetricsProperties extends StepRegistryProperties { */ private HistogramFlavor histogramFlavor = HistogramFlavor.EXPLICIT_BUCKET_HISTOGRAM; - /** - * Per meter histogram type to be preferred when histogram publishing is enabled. - */ - private Map histogramFlavorPerMeter = new LinkedHashMap<>(); - /** * Max scale to use for exponential histograms, if configured. */ @@ -75,15 +70,14 @@ public class OtlpMetricsProperties extends StepRegistryProperties { private int maxBucketCount = 160; /** - * Per meter number of max buckets used for exponential histograms, if configured. - * This has no effect on explicit bucket histograms. + * Time unit for exported metrics. */ - private Map maxBucketsPerMeter = new LinkedHashMap<>(); + private TimeUnit baseTimeUnit = TimeUnit.MILLISECONDS; /** - * Time unit for exported metrics. + * Per-meter properties that can be used to override defaults. */ - private TimeUnit baseTimeUnit = TimeUnit.MILLISECONDS; + private Map meter = new LinkedHashMap<>(); public String getUrl() { return this.url; @@ -117,14 +111,6 @@ public class OtlpMetricsProperties extends StepRegistryProperties { this.histogramFlavor = histogramFlavor; } - public Map getHistogramFlavorPerMeter() { - return this.histogramFlavorPerMeter; - } - - public void setHistogramFlavorPerMeter(Map histogramFlavorPerMeter) { - this.histogramFlavorPerMeter = histogramFlavorPerMeter; - } - public int getMaxScale() { return this.maxScale; } @@ -141,14 +127,6 @@ public class OtlpMetricsProperties extends StepRegistryProperties { this.maxBucketCount = maxBucketCount; } - public Map getMaxBucketsPerMeter() { - return this.maxBucketsPerMeter; - } - - public void setMaxBucketsPerMeter(Map maxBucketsPerMeter) { - this.maxBucketsPerMeter = maxBucketsPerMeter; - } - public TimeUnit getBaseTimeUnit() { return this.baseTimeUnit; } @@ -157,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 abb1178f6bb..d3f9c4838b8 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}. @@ -90,12 +93,12 @@ class OtlpMetricsPropertiesConfigAdapter extends StepRegistryPropertiesConfigAda @Override public Map histogramFlavorPerMeter() { - return get(OtlpMetricsProperties::getHistogramFlavorPerMeter, OtlpConfig.super::histogramFlavorPerMeter); + return get(perMeter(Meter::getHistogramFlavor), OtlpConfig.super::histogramFlavorPerMeter); } @Override public Map maxBucketsPerMeter() { - return get(OtlpMetricsProperties::getMaxBucketsPerMeter, OtlpConfig.super::maxBucketsPerMeter); + return get(perMeter(Meter::getMaxBucketCount), OtlpConfig.super::maxBucketsPerMeter); } @Override @@ -113,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 723202318a4..7f050f16508 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; @@ -117,8 +118,9 @@ class OtlpMetricsPropertiesConfigAdapterTests { @Test void whenPropertiesHistogramFlavorPerMeterIsSetAdapterHistogramFlavorPerMeterReturnsIt() { - this.properties - .setHistogramFlavorPerMeter(Map.of("my.histograms", HistogramFlavor.BASE2_EXPONENTIAL_BUCKET_HISTOGRAM)); + 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); } @@ -152,7 +154,9 @@ class OtlpMetricsPropertiesConfigAdapterTests { @Test void whenPropertiesMaxBucketsPerMeterIsSetAdapterMaxBucketsPerMeterReturnsIt() { - this.properties.setMaxBucketsPerMeter(Map.of("my.histograms", 111)); + Meter meterProperties = new Meter(); + meterProperties.setMaxBucketCount(111); + this.properties.getMeter().put("my.histograms", meterProperties); assertThat(createAdapter().maxBucketsPerMeter()).containsEntry("my.histograms", 111); } 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 843c5fd3aa0..2809e84a735 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 @@ -37,11 +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()); + assertThat(properties.getMeter()).isEmpty(); } } diff --git a/spring-boot-project/spring-boot-dependencies/build.gradle b/spring-boot-project/spring-boot-dependencies/build.gradle index 3da4e7e12bd..9bf051754dd 100644 --- a/spring-boot-project/spring-boot-dependencies/build.gradle +++ b/spring-boot-project/spring-boot-dependencies/build.gradle @@ -1548,7 +1548,7 @@ bom { releaseNotes("https://github.com/apache/maven-war-plugin/releases/tag/maven-war-plugin-{version}") } } - library("Micrometer", "1.15.0-RC1") { + library("Micrometer", "1.15.0-SNAPSHOT") { considerSnapshots() group("io.micrometer") { modules = [