From 6be37b0f1406c3cd1a60a04acf2cac1d5cc45b7a Mon Sep 17 00:00:00 2001 From: Lenin Jaganathan Date: Thu, 8 Aug 2024 03:00:52 -0700 Subject: [PATCH] Support bucket configuration for Histograms --- .../registry/otlp/OtlpMeterRegistry.java | 12 +++++--- .../core/instrument/AbstractTimerBuilder.java | 7 +++++ .../core/instrument/DistributionSummary.java | 7 +++++ .../core/instrument/LongTaskTimer.java | 7 +++++ .../DistributionStatisticConfig.java | 29 +++++++++++++++++++ 5 files changed, 58 insertions(+), 4 deletions(-) diff --git a/implementations/micrometer-registry-otlp/src/main/java/io/micrometer/registry/otlp/OtlpMeterRegistry.java b/implementations/micrometer-registry-otlp/src/main/java/io/micrometer/registry/otlp/OtlpMeterRegistry.java index abceb6adb4..9b17121c1c 100644 --- a/implementations/micrometer-registry-otlp/src/main/java/io/micrometer/registry/otlp/OtlpMeterRegistry.java +++ b/implementations/micrometer-registry-otlp/src/main/java/io/micrometer/registry/otlp/OtlpMeterRegistry.java @@ -266,6 +266,7 @@ protected TimeUnit getBaseTimeUnit() { protected DistributionStatisticConfig defaultHistogramConfig() { return DistributionStatisticConfig.builder() .expiry(this.config.step()) + .maxBucketCount(this.config.maxBucketCount()) .build() .merge(DistributionStatisticConfig.DEFAULT); } @@ -405,11 +406,14 @@ static Histogram getHistogram(final Clock clock, final DistributionStatisticConf minimumExpectedValue = 0.0; } + final int maxBucketCount = distributionStatisticConfig.getMaxBucketCount() != null ? + distributionStatisticConfig.getMaxBucketCount() : otlpConfig.maxBucketCount(); return otlpConfig.aggregationTemporality() == AggregationTemporality.DELTA - ? new DeltaBase2ExponentialHistogram(otlpConfig.maxScale(), otlpConfig.maxBucketCount(), - minimumExpectedValue, baseTimeUnit, clock, otlpConfig.step().toMillis()) - : new CumulativeBase2ExponentialHistogram(otlpConfig.maxScale(), otlpConfig.maxBucketCount(), - minimumExpectedValue, baseTimeUnit); + ? new DeltaBase2ExponentialHistogram(otlpConfig.maxScale(), + maxBucketCount, minimumExpectedValue, baseTimeUnit, + clock, otlpConfig.step().toMillis()) + : new CumulativeBase2ExponentialHistogram(otlpConfig.maxScale(), + maxBucketCount, minimumExpectedValue, baseTimeUnit); } Histogram explicitBucketHistogram = getExplicitBucketHistogram(clock, distributionStatisticConfig, diff --git a/micrometer-core/src/main/java/io/micrometer/core/instrument/AbstractTimerBuilder.java b/micrometer-core/src/main/java/io/micrometer/core/instrument/AbstractTimerBuilder.java index daa58cadde..5ba846d90b 100644 --- a/micrometer-core/src/main/java/io/micrometer/core/instrument/AbstractTimerBuilder.java +++ b/micrometer-core/src/main/java/io/micrometer/core/instrument/AbstractTimerBuilder.java @@ -194,6 +194,13 @@ public B maximumExpectedValue(@Nullable Duration max) { return (B) this; } + public B maxBucketCount(@Nullable Integer maxBucketCount) { + if (maxBucketCount != null) { + this.distributionConfigBuilder.maxBucketCount(maxBucketCount); + } + return (B) this; + } + /** * Statistics emanating from a timer like max, percentiles, and histogram counts decay * over time to give greater weight to recent samples (exception: histogram counts are diff --git a/micrometer-core/src/main/java/io/micrometer/core/instrument/DistributionSummary.java b/micrometer-core/src/main/java/io/micrometer/core/instrument/DistributionSummary.java index 5c2f46e052..50b7125a28 100644 --- a/micrometer-core/src/main/java/io/micrometer/core/instrument/DistributionSummary.java +++ b/micrometer-core/src/main/java/io/micrometer/core/instrument/DistributionSummary.java @@ -345,6 +345,13 @@ public Builder maximumExpectedValue(@Nullable Double max) { return this; } + public Builder maxBucketCount(@Nullable Integer maxBucketCount) { + if (maxBucketCount != null) { + this.distributionConfigBuilder.maxBucketCount(maxBucketCount); + } + return this; + } + /** * Statistics emanating from a distribution summary like max, percentiles, and * histogram counts decay over time to give greater weight to recent samples diff --git a/micrometer-core/src/main/java/io/micrometer/core/instrument/LongTaskTimer.java b/micrometer-core/src/main/java/io/micrometer/core/instrument/LongTaskTimer.java index e04a757cf6..c19a4ef67f 100644 --- a/micrometer-core/src/main/java/io/micrometer/core/instrument/LongTaskTimer.java +++ b/micrometer-core/src/main/java/io/micrometer/core/instrument/LongTaskTimer.java @@ -386,6 +386,13 @@ public Builder maximumExpectedValue(@Nullable Duration max) { return this; } + public Builder maxBucketCount(@Nullable Integer maxBucketCount) { + if (maxBucketCount != null) { + this.distributionConfigBuilder.maxBucketCount(maxBucketCount); + } + return this; + } + /** * Statistics emanating from a timer like max, percentiles, and histogram counts * decay over time to give greater weight to recent samples (exception: histogram diff --git a/micrometer-core/src/main/java/io/micrometer/core/instrument/distribution/DistributionStatisticConfig.java b/micrometer-core/src/main/java/io/micrometer/core/instrument/distribution/DistributionStatisticConfig.java index 9bc0b20a25..eeef6eb7f2 100644 --- a/micrometer-core/src/main/java/io/micrometer/core/instrument/distribution/DistributionStatisticConfig.java +++ b/micrometer-core/src/main/java/io/micrometer/core/instrument/distribution/DistributionStatisticConfig.java @@ -22,6 +22,7 @@ import java.time.Duration; import java.util.NavigableSet; import java.util.TreeSet; +import java.util.stream.Collectors; import java.util.stream.LongStream; /** @@ -41,6 +42,7 @@ public class DistributionStatisticConfig implements Mergeable getHistogramBuckets(boolean supportsAggregablePercen } } + if (maxBucketCount != null && buckets.size() > maxBucketCount) { + return buckets.stream().limit(maxBucketCount).collect(Collectors.toCollection(TreeSet::new)); + } + return buckets; } @@ -210,6 +220,11 @@ public Double getMaximumExpectedValueAsDouble() { return maximumExpectedValue; } + @Nullable + public Integer getMaxBucketCount() { + return maxBucketCount; + } + /** * Statistics like max, percentiles, and histogram counts decay over time to give * greater weight to recent samples (exception: histogram counts are cumulative for @@ -453,6 +468,16 @@ public Builder bufferLength(@Nullable Integer bufferLength) { return this; } + /** + * Restricts the number of buckets/bin ranges used in histogram. + * @param maxBucketCount maximum number of buckets + * @return This buffer + */ + public Builder maxBucketCount(@Nullable Integer maxBucketCount) { + config.maxBucketCount = maxBucketCount; + return this; + } + /** * @return A new immutable distribution configuration. */ @@ -489,6 +514,10 @@ private void validate(DistributionStatisticConfig distributionStatisticConfig) { + ")."); } + if (config.maxBucketCount != null && config.maxBucketCount <= 0) { + rejectConfig("maxBucketCount (" + config.maxBucketCount + ") must be greater than zero"); + } + if (distributionStatisticConfig.getServiceLevelObjectiveBoundaries() != null) { for (double slo : distributionStatisticConfig.getServiceLevelObjectiveBoundaries()) { if (slo <= 0) {