Skip to content

Commit

Permalink
Add capability to have configurable aggregation temporality for OTLP …
Browse files Browse the repository at this point in the history
…Registry (#3625)

OTLP format supports delta and cumulative temporality. This adds the capability to export meters with delta temporality. Below are some behaviours this PR includes
* capability to configure aggregation Temporality via property `otlp.aggregationTemporality`
* Delta Temporality is supported by using StepMeters wherever applicable
* Capability to export max as part of the HistogramDataPoint for Delta Temporality

There are some remaining issues with using delta temporality. Fixes for these will be made as follow-ups.
* max value in histogram is not right
* histogram counts are not right
* partial steps may not publish correct values

Closes gh-3145

Co-authored-by: Jonatan Ivanov <[email protected]>
  • Loading branch information
lenin-jaganathan and jonatan-ivanov authored Apr 10, 2023
1 parent 3c6e834 commit b828fe3
Show file tree
Hide file tree
Showing 14 changed files with 752 additions and 88 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
/*
* Copyright 2023 VMware, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.micrometer.registry.otlp;

/**
* AggregationTemporality defines the way additive values are expressed.
*
* @see <a href=
* "https://opentelemetry.io/docs/reference/specification/metrics/data-model/#temporality">OTLP
* Temporality</a>
* @author Lenin Jaganathan
* @since 1.11.0
*/
public enum AggregationTemporality {

/**
* Reported values do not incorporate previous measurements.
*/
DELTA,

/**
* Reported values incorporate previous measurements.
*/
CUMULATIVE;

public static io.opentelemetry.proto.metrics.v1.AggregationTemporality toOtlpAggregationTemporality(
AggregationTemporality aggregationTemporality) {
switch (aggregationTemporality) {
case DELTA:
return io.opentelemetry.proto.metrics.v1.AggregationTemporality.AGGREGATION_TEMPORALITY_DELTA;
case CUMULATIVE:
return io.opentelemetry.proto.metrics.v1.AggregationTemporality.AGGREGATION_TEMPORALITY_CUMULATIVE;
default:
return io.opentelemetry.proto.metrics.v1.AggregationTemporality.UNRECOGNIZED;
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,13 @@
import static io.micrometer.core.instrument.config.MeterRegistryConfigValidator.*;
import static io.micrometer.core.instrument.config.validate.PropertyValidator.getString;
import static io.micrometer.core.instrument.config.validate.PropertyValidator.getUrlString;
import static io.micrometer.core.instrument.config.validate.PropertyValidator.getEnum;

/**
* Config for {@link OtlpMeterRegistry}.
*
* @author Tommy Ludwig
* @author Lenin Jaganathan
* @since 1.9.0
*/
public interface OtlpConfig extends PushRegistryConfig {
Expand Down Expand Up @@ -88,6 +90,21 @@ default Map<String, String> resourceAttributes() {
return resourceAttributes;
}

/**
* {@link AggregationTemporality} of the OtlpMeterRegistry. This determines whether
* the meters should be cumulative(AGGREGATION_TEMPORALITY_CUMULATIVE) or
* step/delta(AGGREGATION_TEMPORALITY_DELTA).
* @return the aggregationTemporality for OtlpRegistry
* @see <a href=
* "https://opentelemetry.io/docs/reference/specification/metrics/data-model/#temporality">OTLP
* Temporality</a>
* @since 1.11.0
*/
default AggregationTemporality aggregationTemporality() {
return getEnum(this, AggregationTemporality.class, "aggregationTemporality")
.orElse(AggregationTemporality.CUMULATIVE);
}

/**
* Additional headers to send with exported metrics. This may be needed for
* authorization headers, for example.
Expand Down Expand Up @@ -128,7 +145,8 @@ default Map<String, String> headers() {
@Override
default Validated<?> validate() {
return checkAll(this, c -> PushRegistryConfig.validate(c), checkRequired("url", OtlpConfig::url),
check("resourceAttributes", OtlpConfig::resourceAttributes));
check("resourceAttributes", OtlpConfig::resourceAttributes),
check("aggregationTemporality", OtlpConfig::aggregationTemporality));
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,11 @@

import java.util.concurrent.TimeUnit;

class OtlpCounter extends CumulativeCounter implements StartTimeAwareMeter {
class OtlpCumulativeCounter extends CumulativeCounter implements StartTimeAwareMeter {

private final long startTimeNanos;

OtlpCounter(Id id, Clock clock) {
OtlpCumulativeCounter(Id id, Clock clock) {
super(id);
this.startTimeNanos = TimeUnit.MILLISECONDS.toNanos(clock.wallTime());
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2022 VMware, Inc.
* Copyright 2023 VMware, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -23,7 +23,7 @@
import java.time.Duration;
import java.util.concurrent.TimeUnit;

class OtlpDistributionSummary extends CumulativeDistributionSummary implements StartTimeAwareMeter {
class OtlpCumulativeDistributionSummary extends CumulativeDistributionSummary implements StartTimeAwareMeter {

private static final CountAtBucket[] EMPTY_HISTOGRAM = new CountAtBucket[0];

Expand All @@ -32,19 +32,13 @@ class OtlpDistributionSummary extends CumulativeDistributionSummary implements S
@Nullable
private final Histogram monotonicBucketCountHistogram;

OtlpDistributionSummary(Id id, Clock clock, DistributionStatisticConfig distributionStatisticConfig, double scale,
boolean supportsAggregablePercentiles) {
OtlpCumulativeDistributionSummary(Id id, Clock clock, DistributionStatisticConfig distributionStatisticConfig,
double scale, boolean supportsAggregablePercentiles) {
super(id, clock, DistributionStatisticConfig.builder()
.percentilesHistogram(false) // avoid
// a
// histogram
// for
// percentiles/SLOs
// in
// the
// super
.serviceLevelObjectives() // we will use a different implementation here
// instead
// avoid a histogram for percentiles/SLOs in the super
.percentilesHistogram(false)
// we will use a different implementation here instead
.serviceLevelObjectives()
.build()
.merge(distributionStatisticConfig), scale, false);
this.startTimeNanos = TimeUnit.MILLISECONDS.toNanos(clock.wallTime());
Expand All @@ -55,10 +49,8 @@ class OtlpDistributionSummary extends CumulativeDistributionSummary implements S
if (distributionStatisticConfig.isPublishingHistogram()) {
this.monotonicBucketCountHistogram = new TimeWindowFixedBoundaryHistogram(clock,
DistributionStatisticConfig.builder()
.expiry(Duration.ofDays(1825)) // effectively
// never
// roll
// over
// effectively never roll over
.expiry(Duration.ofDays(1825))
.bufferLength(1)
.build()
.merge(distributionStatisticConfig),
Expand All @@ -84,13 +76,9 @@ public HistogramSnapshot takeSnapshot() {
return snapshot;
}

CountAtBucket[] histogramCounts = this.monotonicBucketCountHistogram.takeSnapshot(0, 0, 0).histogramCounts();
return new HistogramSnapshot(snapshot.count(), snapshot.total(), snapshot.max(), snapshot.percentileValues(),
histogramCounts(), snapshot::outputSummary);
}

private CountAtBucket[] histogramCounts() {
return this.monotonicBucketCountHistogram == null ? EMPTY_HISTOGRAM
: this.monotonicBucketCountHistogram.takeSnapshot(0, 0, 0).histogramCounts();
histogramCounts, snapshot::outputSummary);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,11 @@
import java.util.concurrent.TimeUnit;
import java.util.function.ToDoubleFunction;

class OtlpFunctionCounter<T> extends CumulativeFunctionCounter<T> implements StartTimeAwareMeter {
class OtlpCumulativeFunctionCounter<T> extends CumulativeFunctionCounter<T> implements StartTimeAwareMeter {

private final long startTimeNanos;

OtlpFunctionCounter(Id id, T obj, ToDoubleFunction<T> f, Clock clock) {
OtlpCumulativeFunctionCounter(Id id, T obj, ToDoubleFunction<T> f, Clock clock) {
super(id, obj, f);
this.startTimeNanos = TimeUnit.MILLISECONDS.toNanos(clock.wallTime());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,11 @@
import java.util.function.ToDoubleFunction;
import java.util.function.ToLongFunction;

class OtlpFunctionTimer<T> extends CumulativeFunctionTimer<T> implements StartTimeAwareMeter {
class OtlpCumulativeFunctionTimer<T> extends CumulativeFunctionTimer<T> implements StartTimeAwareMeter {

private final long startTimeNanos;

OtlpFunctionTimer(Id id, T obj, ToLongFunction<T> countFunction, ToDoubleFunction<T> totalTimeFunction,
OtlpCumulativeFunctionTimer(Id id, T obj, ToLongFunction<T> countFunction, ToDoubleFunction<T> totalTimeFunction,
TimeUnit totalTimeFunctionUnit, TimeUnit baseTimeUnit, Clock clock) {
super(id, obj, countFunction, totalTimeFunction, totalTimeFunctionUnit, baseTimeUnit);
this.startTimeNanos = TimeUnit.MILLISECONDS.toNanos(clock.wallTime());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,11 @@

import java.util.concurrent.TimeUnit;

class OtlpLongTaskTimer extends CumulativeHistogramLongTaskTimer implements StartTimeAwareMeter {
class OtlpCumulativeLongTaskTimer extends CumulativeHistogramLongTaskTimer implements StartTimeAwareMeter {

private final long startTimeNanos;

OtlpLongTaskTimer(Id id, Clock clock, TimeUnit baseTimeUnit,
OtlpCumulativeLongTaskTimer(Id id, Clock clock, TimeUnit baseTimeUnit,
DistributionStatisticConfig distributionStatisticConfig) {
super(id, clock, baseTimeUnit, distributionStatisticConfig);
this.startTimeNanos = TimeUnit.MILLISECONDS.toNanos(clock.wallTime());
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2022 VMware, Inc.
* Copyright 2023 VMware, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -25,26 +25,20 @@
import java.time.Duration;
import java.util.concurrent.TimeUnit;

class OtlpTimer extends CumulativeTimer implements StartTimeAwareMeter {
class OtlpCumulativeTimer extends CumulativeTimer implements StartTimeAwareMeter {

private final long startTimeNanos;

@Nullable
private final Histogram monotonicCountBucketHistogram;

OtlpTimer(Id id, Clock clock, DistributionStatisticConfig distributionStatisticConfig, PauseDetector pauseDetector,
TimeUnit baseTimeUnit) {
OtlpCumulativeTimer(Id id, Clock clock, DistributionStatisticConfig distributionStatisticConfig,
PauseDetector pauseDetector, TimeUnit baseTimeUnit) {
super(id, clock, DistributionStatisticConfig.builder()
.percentilesHistogram(false) // avoid
// a
// histogram
// for
// percentiles/SLOs
// in
// the
// super
.serviceLevelObjectives() // we will use a different implementation here
// instead
// avoid a histogram for percentiles/SLOs in the super
.percentilesHistogram(false)
// we will use a different implementation here instead
.serviceLevelObjectives()
.build()
.merge(distributionStatisticConfig), pauseDetector, baseTimeUnit, false);
this.startTimeNanos = TimeUnit.MILLISECONDS.toNanos(clock.wallTime());
Expand All @@ -54,10 +48,8 @@ class OtlpTimer extends CumulativeTimer implements StartTimeAwareMeter {
if (distributionStatisticConfig.isPublishingHistogram()) {
this.monotonicCountBucketHistogram = new TimeWindowFixedBoundaryHistogram(clock,
DistributionStatisticConfig.builder()
.expiry(Duration.ofDays(1825)) // effectively
// never
// roll
// over
// effectively never roll over
.expiry(Duration.ofDays(1825))
.bufferLength(1)
.build()
.merge(distributionStatisticConfig),
Expand Down
Loading

0 comments on commit b828fe3

Please sign in to comment.