diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/export/otlp/OtlpProperties.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/export/otlp/OtlpProperties.java index e9a038d3e664..5ad71476c6a7 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/export/otlp/OtlpProperties.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/export/otlp/OtlpProperties.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2023 the original author or authors. + * Copyright 2012-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,6 +20,7 @@ import java.util.concurrent.TimeUnit; import io.micrometer.registry.otlp.AggregationTemporality; +import io.micrometer.registry.otlp.HistogramFlavor; import org.springframework.boot.actuate.autoconfigure.metrics.export.properties.StepRegistryProperties; import org.springframework.boot.context.properties.ConfigurationProperties; @@ -57,6 +58,22 @@ public class OtlpProperties extends StepRegistryProperties { */ private Map headers; + /** + * Histogram type to be preferred when histogram publishing is enabled. + */ + private HistogramFlavor histogramFlavor = HistogramFlavor.EXPLICIT_BUCKET_HISTOGRAM; + + /** + * 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. + */ + private int maxBucketCount = 160; + /** * Time unit for exported metrics. */ @@ -97,6 +114,30 @@ public void setHeaders(Map headers) { this.headers = headers; } + public HistogramFlavor getHistogramFlavor() { + return this.histogramFlavor; + } + + public void setHistogramFlavor(HistogramFlavor histogramFlavor) { + this.histogramFlavor = histogramFlavor; + } + + public int getMaxScale() { + return this.maxScale; + } + + public void setMaxScale(int maxScale) { + this.maxScale = maxScale; + } + + public int getMaxBucketCount() { + return this.maxBucketCount; + } + + public void setMaxBucketCount(int maxBucketCount) { + this.maxBucketCount = maxBucketCount; + } + public TimeUnit getBaseTimeUnit() { return this.baseTimeUnit; } diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/export/otlp/OtlpPropertiesConfigAdapter.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/export/otlp/OtlpPropertiesConfigAdapter.java index d30e8b7eb064..0f6d5947ebdb 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/export/otlp/OtlpPropertiesConfigAdapter.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/export/otlp/OtlpPropertiesConfigAdapter.java @@ -22,6 +22,7 @@ import java.util.concurrent.TimeUnit; 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.properties.StepRegistryPropertiesConfigAdapter; @@ -98,6 +99,21 @@ public Map headers() { return get(OtlpProperties::getHeaders, OtlpConfig.super::headers); } + @Override + public HistogramFlavor histogramFlavor() { + return get(OtlpProperties::getHistogramFlavor, OtlpConfig.super::histogramFlavor); + } + + @Override + public int maxScale() { + return get(OtlpProperties::getMaxScale, OtlpConfig.super::maxScale); + } + + @Override + public int maxBucketCount() { + return get(OtlpProperties::getMaxBucketCount, OtlpConfig.super::maxBucketCount); + } + @Override public TimeUnit baseTimeUnit() { return get(OtlpProperties::getBaseTimeUnit, OtlpConfig.super::baseTimeUnit); diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/export/otlp/OtlpPropertiesConfigAdapterTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/export/otlp/OtlpPropertiesConfigAdapterTests.java index 5413e8c3a2f6..78c97b35c0d3 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/export/otlp/OtlpPropertiesConfigAdapterTests.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/export/otlp/OtlpPropertiesConfigAdapterTests.java @@ -21,6 +21,7 @@ import java.util.concurrent.TimeUnit; import io.micrometer.registry.otlp.AggregationTemporality; +import io.micrometer.registry.otlp.HistogramFlavor; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -85,6 +86,39 @@ void whenPropertiesHeadersIsSetAdapterHeadersReturnsIt() { assertThat(createAdapter().headers()).containsEntry("header", "value"); } + @Test + void whenPropertiesHistogramFlavorIsNotSetAdapterHistogramFlavorReturnsExplicitBucketHistogram() { + assertThat(createAdapter().histogramFlavor()).isSameAs(HistogramFlavor.EXPLICIT_BUCKET_HISTOGRAM); + } + + @Test + void whenPropertiesHistogramFlavorIsSetAdapterHistogramFlavorReturnsIt() { + this.properties.setHistogramFlavor(HistogramFlavor.BASE2_EXPONENTIAL_BUCKET_HISTOGRAM); + assertThat(createAdapter().histogramFlavor()).isSameAs(HistogramFlavor.BASE2_EXPONENTIAL_BUCKET_HISTOGRAM); + } + + @Test + void whenPropertiesMaxScaleIsNotSetAdapterMaxScaleReturns20() { + assertThat(createAdapter().maxScale()).isEqualTo(20); + } + + @Test + void whenPropertiesMaxScaleIsSetAdapterMaxScaleReturnsIt() { + this.properties.setMaxScale(5); + assertThat(createAdapter().maxScale()).isEqualTo(5); + } + + @Test + void whenPropertiesMaxBucketCountIsNotSetAdapterMaxBucketCountReturns160() { + assertThat(createAdapter().maxBucketCount()).isEqualTo(160); + } + + @Test + void whenPropertiesMaxBucketCountIsSetAdapterMaxBucketCountReturnsIt() { + this.properties.setMaxBucketCount(6); + assertThat(createAdapter().maxBucketCount()).isEqualTo(6); + } + @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/OtlpPropertiesTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/export/otlp/OtlpPropertiesTests.java index 3046e2279dca..1ecf8fb7c4c2 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/export/otlp/OtlpPropertiesTests.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/export/otlp/OtlpPropertiesTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2023 the original author or authors. + * Copyright 2012-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -37,6 +37,9 @@ void defaultValuesAreConsistent() { assertStepRegistryDefaultValues(properties, config); assertThat(properties.getUrl()).isEqualTo(config.url()); assertThat(properties.getAggregationTemporality()).isSameAs(config.aggregationTemporality()); + assertThat(properties.getHistogramFlavor()).isSameAs(config.histogramFlavor()); + assertThat(properties.getMaxScale()).isEqualTo(config.maxScale()); + assertThat(properties.getMaxBucketCount()).isEqualTo(config.maxBucketCount()); assertThat(properties.getBaseTimeUnit()).isSameAs(config.baseTimeUnit()); }