Skip to content

Commit

Permalink
Fix merge conflicts and update since field
Browse files Browse the repository at this point in the history
  • Loading branch information
lenin-jaganathan committed Jul 19, 2024
1 parent c61f1fe commit 0ba532c
Show file tree
Hide file tree
Showing 10 changed files with 190 additions and 189 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,6 @@
import io.micrometer.core.ipc.http.HttpUrlConnectionSender;
import io.micrometer.registry.otlp.internal.CumulativeBase2ExponentialHistogram;
import io.micrometer.registry.otlp.internal.DeltaBase2ExponentialHistogram;
import io.micrometer.registry.otlp.internal.ExponentialHistogramSnapShot;
import io.opentelemetry.proto.collector.metrics.v1.ExportMetricsServiceRequest;
import io.opentelemetry.proto.common.v1.AnyValue;
import io.opentelemetry.proto.common.v1.KeyValue;
Expand Down Expand Up @@ -69,11 +68,6 @@ public class OtlpMeterRegistry extends PushMeterRegistry {

private static final ThreadFactory DEFAULT_THREAD_FACTORY = new NamedThreadFactory("otlp-metrics-publisher");

private static final ExponentialHistogramDataPoint.Buckets EMPTY_EXPONETIAL_HISTOGRAM_BUCKETS = ExponentialHistogramDataPoint.Buckets
.newBuilder()
.addAllBucketCounts(Collections.emptyList())
.build();

private static final double[] EMPTY_SLO_WITH_POSITIVE_INF = new double[] { Double.POSITIVE_INFINITY };

private static final String TELEMETRY_SDK_NAME = "telemetry.sdk.name";
Expand Down Expand Up @@ -351,125 +345,6 @@ private long getInitialDelay() {
return stepMillis - (clock.wallTime() % stepMillis) + 1;
}

// VisibleForTesting
Metric writeHistogramSupport(HistogramSupport histogramSupport) {
Metric.Builder metricBuilder = getMetricBuilder(histogramSupport.getId());
boolean isTimeBased = histogramSupport instanceof Timer || histogramSupport instanceof LongTaskTimer;
HistogramSnapshot histogramSnapshot = histogramSupport.takeSnapshot();

Iterable<? extends KeyValue> tags = getTagsForId(histogramSupport.getId());
long startTimeNanos = getStartTimeNanos(histogramSupport);
double total = isTimeBased ? histogramSnapshot.total(getBaseTimeUnit()) : histogramSnapshot.total();
long count = histogramSnapshot.count();

// if percentiles configured, use summary
if (histogramSnapshot.percentileValues().length != 0) {
SummaryDataPoint.Builder summaryData = SummaryDataPoint.newBuilder()
.addAllAttributes(tags)
.setStartTimeUnixNano(startTimeNanos)
.setTimeUnixNano(getTimeUnixNano())
.setSum(total)
.setCount(count);
for (ValueAtPercentile percentile : histogramSnapshot.percentileValues()) {
summaryData.addQuantileValues(SummaryDataPoint.ValueAtQuantile.newBuilder()
.setQuantile(percentile.percentile())
.setValue(TimeUtils.convert(percentile.value(), TimeUnit.NANOSECONDS, getBaseTimeUnit())));
}
metricBuilder.setSummary(Summary.newBuilder().addDataPoints(summaryData));
return metricBuilder.build();
}

ExponentialHistogramSnapShot exponentialHistogramSnapShot = getExponentialHistogramSnapShot(histogramSupport);
if (exponentialHistogramSnapShot != null) {
ExponentialHistogramDataPoint.Builder exponentialDataPoint = ExponentialHistogramDataPoint.newBuilder()
.addAllAttributes(tags)
.setStartTimeUnixNano(startTimeNanos)
.setTimeUnixNano(getTimeUnixNano())
.setCount(count)
.setSum(total)
.setScale(exponentialHistogramSnapShot.scale())
.setZeroCount(exponentialHistogramSnapShot.zeroCount())
.setZeroThreshold(exponentialHistogramSnapShot.zeroThreshold())
.setPositive(ExponentialHistogramDataPoint.Buckets.newBuilder()
.addAllBucketCounts(exponentialHistogramSnapShot.bucketsCount())
.setOffset(exponentialHistogramSnapShot.offset())
.build())
// Micrometer doesn't support negative recordings.
.setNegative(EMPTY_EXPONETIAL_HISTOGRAM_BUCKETS);

if (isDelta()) {
exponentialDataPoint
.setMax(isTimeBased ? histogramSnapshot.max(getBaseTimeUnit()) : histogramSnapshot.max());
}

return metricBuilder
.setExponentialHistogram(ExponentialHistogram.newBuilder()
.setAggregationTemporality(otlpAggregationTemporality)
.addDataPoints(exponentialDataPoint)
.build())
.build();
}

HistogramDataPoint.Builder histogramDataPoint = HistogramDataPoint.newBuilder()
.addAllAttributes(tags)
.setStartTimeUnixNano(startTimeNanos)
.setTimeUnixNano(getTimeUnixNano())
.setSum(total)
.setCount(count);

if (isDelta()) {
histogramDataPoint.setMax(isTimeBased ? histogramSnapshot.max(getBaseTimeUnit()) : histogramSnapshot.max());
}
// if histogram enabled, add histogram buckets
if (histogramSnapshot.histogramCounts().length != 0) {
for (CountAtBucket countAtBucket : histogramSnapshot.histogramCounts()) {
if (countAtBucket.bucket() != Double.POSITIVE_INFINITY) {
// OTLP expects explicit bounds to not contain POSITIVE_INFINITY but
// there should be a
// bucket count representing values between last bucket and
// POSITIVE_INFINITY.
histogramDataPoint.addExplicitBounds(
isTimeBased ? countAtBucket.bucket(getBaseTimeUnit()) : countAtBucket.bucket());
}
histogramDataPoint.addBucketCounts((long) countAtBucket.count());
}
metricBuilder.setHistogram(io.opentelemetry.proto.metrics.v1.Histogram.newBuilder()
.setAggregationTemporality(otlpAggregationTemporality)
.addDataPoints(histogramDataPoint));
return metricBuilder.build();
}

return metricBuilder
.setHistogram(io.opentelemetry.proto.metrics.v1.Histogram.newBuilder()
.setAggregationTemporality(otlpAggregationTemporality)
.addDataPoints(histogramDataPoint))
.build();
}

@Nullable
private static ExponentialHistogramSnapShot getExponentialHistogramSnapShot(
final HistogramSupport histogramSupport) {
if (histogramSupport instanceof OtlpHistogramSupport) {
return ((OtlpHistogramSupport) histogramSupport).getExponentialHistogramSnapShot();
}

return null;
}

// VisibleForTesting
Metric writeFunctionTimer(FunctionTimer functionTimer) {
return getMetricBuilder(functionTimer.getId())
.setHistogram(io.opentelemetry.proto.metrics.v1.Histogram.newBuilder()
.addDataPoints(HistogramDataPoint.newBuilder()
.addAllAttributes(getTagsForId(functionTimer.getId()))
.setStartTimeUnixNano(getStartTimeNanos((functionTimer)))
.setTimeUnixNano(getTimeUnixNano())
.setSum(functionTimer.totalTime(getBaseTimeUnit()))
.setCount((long) functionTimer.count()))
.setAggregationTemporality(otlpAggregationTemporality))
.build();
}

private boolean isCumulative() {
return this.aggregationTemporality == AggregationTemporality.CUMULATIVE;
}
Expand Down Expand Up @@ -516,14 +391,15 @@ static Histogram getHistogram(Clock clock, DistributionStatisticConfig distribut

static Histogram getHistogram(final Clock clock, final DistributionStatisticConfig distributionStatisticConfig,
final OtlpConfig otlpConfig, @Nullable final TimeUnit baseTimeUnit) {
// While publishing to OTLP, we export either Histogram datapoint (Explicit Bucket
// While publishing to OTLP, we export either Histogram datapoint (Explicit
// ExponentialBucket
// or Exponential) / Summary
// datapoint. So, we will make the histogram either of them and not both.
// Though AbstractTimer/Distribution Summary prefers publishing percentiles,
// exporting of histograms over percentiles is preferred in OTLP.
if (distributionStatisticConfig.isPublishingHistogram()) {
if (histogramFlavour(otlpConfig.histogramFlavour(),
distributionStatisticConfig) == HistogramFlavour.BASE2_EXPONENTIAL_BUCKET_HISTOGRAM) {
if (HistogramFlavour.BASE2_EXPONENTIAL_BUCKET_HISTOGRAM
.equals(histogramFlavour(otlpConfig.histogramFlavour(), distributionStatisticConfig))) {
Double minimumExpectedValue = distributionStatisticConfig.getMinimumExpectedValueAsDouble();
if (minimumExpectedValue == null) {
minimumExpectedValue = 0.0;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import io.micrometer.core.instrument.distribution.HistogramSupport;
import io.micrometer.core.instrument.distribution.ValueAtPercentile;
import io.micrometer.core.instrument.util.TimeUtils;
import io.micrometer.registry.otlp.internal.ExponentialHistogramSnapShot;
import io.opentelemetry.proto.common.v1.AnyValue;
import io.opentelemetry.proto.common.v1.KeyValue;
import io.opentelemetry.proto.metrics.v1.*;
Expand All @@ -40,6 +41,11 @@
*/
class OtlpMetricConverter {

private static final ExponentialHistogramDataPoint.Buckets EMPTY_EXPONETIAL_HISTOGRAM_BUCKETS = ExponentialHistogramDataPoint.Buckets
.newBuilder()
.addAllBucketCounts(Collections.emptyList())
.build();

private final Clock clock;

private final Duration step;
Expand Down Expand Up @@ -122,16 +128,35 @@ private void writeHistogramSupport(HistogramSupport histogramSupport) {
Iterable<KeyValue> tags = getKeyValuesForId(id);
long startTimeNanos = getStartTimeNanos(histogramSupport);
double total = isTimeBased ? histogramSnapshot.total(baseTimeUnit) : histogramSnapshot.total();
double max = isTimeBased ? histogramSnapshot.max(baseTimeUnit) : histogramSnapshot.max();
long count = histogramSnapshot.count();

// if percentiles configured, use summary
if (histogramSnapshot.percentileValues().length != 0) {
buildSummaryDataPoint(histogramSupport, tags, startTimeNanos, total, count, isTimeBased, histogramSnapshot);
return;
}

Optional<ExponentialHistogramSnapShot> exponentialHistogramSnapShot = getExponentialHistogramSnapShot(
histogramSupport);
if (exponentialHistogramSnapShot.isPresent()) {
buildExponentialHistogramDataPoint(histogramSupport, tags, startTimeNanos, total, max, count,
exponentialHistogramSnapShot.get());
}
else {
buildHistogramDataPoint(histogramSupport, tags, startTimeNanos, total, count, isTimeBased,
buildHistogramDataPoint(histogramSupport, tags, startTimeNanos, total, max, count, isTimeBased,
histogramSnapshot);
}

}

private static Optional<ExponentialHistogramSnapShot> getExponentialHistogramSnapShot(
final HistogramSupport histogramSupport) {
if (histogramSupport instanceof OtlpHistogramSupport) {
return Optional.ofNullable(((OtlpHistogramSupport) histogramSupport).getExponentialHistogramSnapShot());
}

return Optional.empty();
}

private void writeFunctionTimer(FunctionTimer functionTimer) {
Expand All @@ -151,7 +176,8 @@ private boolean isTimeBasedMeter(Meter.Id id) {
}

private void buildHistogramDataPoint(HistogramSupport histogramSupport, Iterable<KeyValue> tags,
long startTimeNanos, double total, long count, boolean isTimeBased, HistogramSnapshot histogramSnapshot) {
long startTimeNanos, double total, double max, long count, boolean isTimeBased,
HistogramSnapshot histogramSnapshot) {
Metric.Builder metricBuilder = getOrCreateMetricBuilder(histogramSupport.getId(), DataCase.HISTOGRAM);
HistogramDataPoint.Builder histogramDataPoint = HistogramDataPoint.newBuilder()
.addAllAttributes(tags)
Expand All @@ -161,7 +187,7 @@ private void buildHistogramDataPoint(HistogramSupport histogramSupport, Iterable
.setCount(count);

if (isDelta()) {
histogramDataPoint.setMax(isTimeBased ? histogramSnapshot.max(baseTimeUnit) : histogramSnapshot.max());
histogramDataPoint.setMax(max);
}

// if histogram enabled, add histogram buckets
Expand All @@ -180,6 +206,37 @@ private void buildHistogramDataPoint(HistogramSupport histogramSupport, Iterable
setHistogramDataPoint(metricBuilder, histogramDataPoint.build());
}

private void buildExponentialHistogramDataPoint(HistogramSupport histogramSupport, Iterable<KeyValue> tags,
long startTimeNanos, double total, double max, long count,
ExponentialHistogramSnapShot exponentialHistogramSnapShot) {
Metric.Builder metricBuilder = getOrCreateMetricBuilder(histogramSupport.getId(),
DataCase.EXPONENTIAL_HISTOGRAM);
ExponentialHistogramDataPoint.Builder exponentialDataPoint = ExponentialHistogramDataPoint.newBuilder()
.addAllAttributes(tags)
.setStartTimeUnixNano(startTimeNanos)
.setTimeUnixNano(getTimeUnixNano())
.setCount(count)
.setSum(total)
.setScale(exponentialHistogramSnapShot.scale())
.setZeroCount(exponentialHistogramSnapShot.zeroCount())
.setZeroThreshold(exponentialHistogramSnapShot.zeroThreshold());

// Currently, micrometer doesn't support negative recordings hence we will only
// add positive buckets.
if (!exponentialHistogramSnapShot.positive().isEmpty()) {
exponentialDataPoint.setPositive(ExponentialHistogramDataPoint.Buckets.newBuilder()
.addAllBucketCounts(exponentialHistogramSnapShot.positive().bucketCounts())
.setOffset(exponentialHistogramSnapShot.positive().offset())
.build());
}

if (isDelta()) {
exponentialDataPoint.setMax(max);
}

setExponentialHistogramDataPoint(metricBuilder, exponentialDataPoint.build());
}

private void buildSummaryDataPoint(HistogramSupport histogramSupport, Iterable<KeyValue> tags, long startTimeNanos,
double total, long count, boolean isTimeBased, HistogramSnapshot histogramSnapshot) {
Metric.Builder metricBuilder = getOrCreateMetricBuilder(histogramSupport.getId(), DataCase.SUMMARY);
Expand Down Expand Up @@ -220,6 +277,15 @@ private void setHistogramDataPoint(Metric.Builder builder, HistogramDataPoint hi
builder.getHistogramBuilder().addDataPoints(histogramDataPoint);
}

private void setExponentialHistogramDataPoint(Metric.Builder builder,
ExponentialHistogramDataPoint exponentialHistogramDataPoint) {
if (!builder.hasExponentialHistogram()) {
builder.setExponentialHistogram(
ExponentialHistogram.newBuilder().setAggregationTemporality(otlpAggregationTemporality));
}
builder.getExponentialHistogramBuilder().addDataPoints(exponentialHistogramDataPoint);
}

private void setSummaryDataPoint(Metric.Builder builder, SummaryDataPoint.Builder summaryDataPoint) {
if (!builder.hasSummary()) {
builder.setSummary(Summary.newBuilder());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
*/
package io.micrometer.registry.otlp.internal;

import static io.micrometer.registry.otlp.internal.ExponentialHistogramSnapShot.ExponentialBucket.EMPTY_EXPONENTIAL_BUCKET;

import java.util.Arrays;
import java.util.Collections;
import java.util.List;
Expand All @@ -26,17 +28,24 @@
import io.micrometer.core.instrument.distribution.Histogram;
import io.micrometer.core.instrument.distribution.HistogramSnapshot;
import io.micrometer.core.instrument.util.TimeUtils;
import io.micrometer.registry.otlp.internal.ExponentialHistogramSnapShot.ExponentialBucket;

/**
* A ExponentialHistogram implementation that compresses bucket boundaries using an
* exponential formula (Base2 exponent), making it suitable for conveying high dynamic
* range data with small relative error. This is an implementation of the <a href=
* "https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/metrics/data-model.md#exponentialhistogram">Exponential
* Histogram</a> as per the OTLP specification. The internal implementations uses the
* techniques outlined in the OTLP specification mentioned above.
* techniques outlined in the OTLP specification mentioned above. This implementation
* supports only recording positive values (enforced by
* {@link io.micrometer.core.instrument.AbstractTimer#record(long, TimeUnit)}).
* <p>
* <strong> This is an internal class and might have breaking changes, external
* implementations SHOULD NOT rely on this implementation. </strong>
* </p>
*
* @author Lenin Jaganathan
* @since 1.12.0
* @since 1.14.0
*/
public abstract class Base2ExponentialHistogram implements Histogram {

Expand Down Expand Up @@ -115,8 +124,8 @@ public HistogramSnapshot takeSnapshot(final long count, final double total, fina
ExponentialHistogramSnapShot getCurrentValuesSnapshot() {
return (circularCountHolder.isEmpty() && zeroCount.longValue() == 0)
? DefaultExponentialHistogramSnapShot.getEmptySnapshotForScale(scale)
: new DefaultExponentialHistogramSnapShot(scale, getOffset(), zeroCount.longValue(), zeroThreshold,
getBucketCounts());
: new DefaultExponentialHistogramSnapShot(scale, zeroCount.longValue(), zeroThreshold,
new ExponentialBucket(getOffset(), getBucketCounts()), EMPTY_EXPONENTIAL_BUCKET);
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,14 @@

/**
* A {@link Base2ExponentialHistogram} that tracks values cumulatively from first recorded
* value.
* value. *
* <p>
* * <strong> This is an internal class and might have breaking changes, external *
* implementations SHOULD NOT rely on this implementation. </strong> *
* </p>
*
* @author Lenin Jaganathan
* @since 1.12.0
* @since 1.14.0
*/
public class CumulativeBase2ExponentialHistogram extends Base2ExponentialHistogram {

Expand Down
Loading

0 comments on commit 0ba532c

Please sign in to comment.