Skip to content

Commit 718f3c2

Browse files
Fix merge conflicts and update since field
1 parent c61f1fe commit 718f3c2

12 files changed

+189
-193
lines changed

implementations/micrometer-registry-otlp/src/main/java/io/micrometer/registry/otlp/HistogramFlavour.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
* "https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/metrics/sdk_exporters/otlp.md#additional-configuration">OTLP
2323
* Configuration</a>
2424
* @author Lenin Jaganathan
25-
* @since 1.12.0
25+
* @since 1.14.0
2626
*/
2727
public enum HistogramFlavour {
2828

implementations/micrometer-registry-otlp/src/main/java/io/micrometer/registry/otlp/OtlpConfig.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -215,7 +215,7 @@ default Map<String, String> headers() {
215215
* </p>
216216
* @return - histogram flavour to be used
217217
*
218-
* @since 1.12.0
218+
* @since 1.14.0
219219
*/
220220
default HistogramFlavour histogramFlavour() {
221221
String histogramPreference = System.getenv().get("OTEL_EXPORTER_OTLP_METRICS_DEFAULT_HISTOGRAM_AGGREGATION");
@@ -231,7 +231,7 @@ default HistogramFlavour histogramFlavour() {
231231
* {@link io.micrometer.registry.otlp.internal.Base2ExponentialHistogram}
232232
* @return maxScale
233233
*
234-
* @since 1.12.0
234+
* @since 1.14.0
235235
*/
236236
default int maxScale() {
237237
return getInteger(this, "maxScale").orElse(20);
@@ -242,7 +242,7 @@ default int maxScale() {
242242
* {@link io.micrometer.registry.otlp.internal.Base2ExponentialHistogram}
243243
* @return - maxBuckets
244244
*
245-
* @since 1.12.0
245+
* @since 1.14.0
246246
*/
247247
default int maxBucketCount() {
248248
return getInteger(this, "maxBucketCount").orElse(160);

implementations/micrometer-registry-otlp/src/main/java/io/micrometer/registry/otlp/OtlpMeterRegistry.java

Lines changed: 4 additions & 128 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,6 @@
4040
import io.micrometer.core.ipc.http.HttpUrlConnectionSender;
4141
import io.micrometer.registry.otlp.internal.CumulativeBase2ExponentialHistogram;
4242
import io.micrometer.registry.otlp.internal.DeltaBase2ExponentialHistogram;
43-
import io.micrometer.registry.otlp.internal.ExponentialHistogramSnapShot;
4443
import io.opentelemetry.proto.collector.metrics.v1.ExportMetricsServiceRequest;
4544
import io.opentelemetry.proto.common.v1.AnyValue;
4645
import io.opentelemetry.proto.common.v1.KeyValue;
@@ -69,11 +68,6 @@ public class OtlpMeterRegistry extends PushMeterRegistry {
6968

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

72-
private static final ExponentialHistogramDataPoint.Buckets EMPTY_EXPONETIAL_HISTOGRAM_BUCKETS = ExponentialHistogramDataPoint.Buckets
73-
.newBuilder()
74-
.addAllBucketCounts(Collections.emptyList())
75-
.build();
76-
7771
private static final double[] EMPTY_SLO_WITH_POSITIVE_INF = new double[] { Double.POSITIVE_INFINITY };
7872

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

354-
// VisibleForTesting
355-
Metric writeHistogramSupport(HistogramSupport histogramSupport) {
356-
Metric.Builder metricBuilder = getMetricBuilder(histogramSupport.getId());
357-
boolean isTimeBased = histogramSupport instanceof Timer || histogramSupport instanceof LongTaskTimer;
358-
HistogramSnapshot histogramSnapshot = histogramSupport.takeSnapshot();
359-
360-
Iterable<? extends KeyValue> tags = getTagsForId(histogramSupport.getId());
361-
long startTimeNanos = getStartTimeNanos(histogramSupport);
362-
double total = isTimeBased ? histogramSnapshot.total(getBaseTimeUnit()) : histogramSnapshot.total();
363-
long count = histogramSnapshot.count();
364-
365-
// if percentiles configured, use summary
366-
if (histogramSnapshot.percentileValues().length != 0) {
367-
SummaryDataPoint.Builder summaryData = SummaryDataPoint.newBuilder()
368-
.addAllAttributes(tags)
369-
.setStartTimeUnixNano(startTimeNanos)
370-
.setTimeUnixNano(getTimeUnixNano())
371-
.setSum(total)
372-
.setCount(count);
373-
for (ValueAtPercentile percentile : histogramSnapshot.percentileValues()) {
374-
summaryData.addQuantileValues(SummaryDataPoint.ValueAtQuantile.newBuilder()
375-
.setQuantile(percentile.percentile())
376-
.setValue(TimeUtils.convert(percentile.value(), TimeUnit.NANOSECONDS, getBaseTimeUnit())));
377-
}
378-
metricBuilder.setSummary(Summary.newBuilder().addDataPoints(summaryData));
379-
return metricBuilder.build();
380-
}
381-
382-
ExponentialHistogramSnapShot exponentialHistogramSnapShot = getExponentialHistogramSnapShot(histogramSupport);
383-
if (exponentialHistogramSnapShot != null) {
384-
ExponentialHistogramDataPoint.Builder exponentialDataPoint = ExponentialHistogramDataPoint.newBuilder()
385-
.addAllAttributes(tags)
386-
.setStartTimeUnixNano(startTimeNanos)
387-
.setTimeUnixNano(getTimeUnixNano())
388-
.setCount(count)
389-
.setSum(total)
390-
.setScale(exponentialHistogramSnapShot.scale())
391-
.setZeroCount(exponentialHistogramSnapShot.zeroCount())
392-
.setZeroThreshold(exponentialHistogramSnapShot.zeroThreshold())
393-
.setPositive(ExponentialHistogramDataPoint.Buckets.newBuilder()
394-
.addAllBucketCounts(exponentialHistogramSnapShot.bucketsCount())
395-
.setOffset(exponentialHistogramSnapShot.offset())
396-
.build())
397-
// Micrometer doesn't support negative recordings.
398-
.setNegative(EMPTY_EXPONETIAL_HISTOGRAM_BUCKETS);
399-
400-
if (isDelta()) {
401-
exponentialDataPoint
402-
.setMax(isTimeBased ? histogramSnapshot.max(getBaseTimeUnit()) : histogramSnapshot.max());
403-
}
404-
405-
return metricBuilder
406-
.setExponentialHistogram(ExponentialHistogram.newBuilder()
407-
.setAggregationTemporality(otlpAggregationTemporality)
408-
.addDataPoints(exponentialDataPoint)
409-
.build())
410-
.build();
411-
}
412-
413-
HistogramDataPoint.Builder histogramDataPoint = HistogramDataPoint.newBuilder()
414-
.addAllAttributes(tags)
415-
.setStartTimeUnixNano(startTimeNanos)
416-
.setTimeUnixNano(getTimeUnixNano())
417-
.setSum(total)
418-
.setCount(count);
419-
420-
if (isDelta()) {
421-
histogramDataPoint.setMax(isTimeBased ? histogramSnapshot.max(getBaseTimeUnit()) : histogramSnapshot.max());
422-
}
423-
// if histogram enabled, add histogram buckets
424-
if (histogramSnapshot.histogramCounts().length != 0) {
425-
for (CountAtBucket countAtBucket : histogramSnapshot.histogramCounts()) {
426-
if (countAtBucket.bucket() != Double.POSITIVE_INFINITY) {
427-
// OTLP expects explicit bounds to not contain POSITIVE_INFINITY but
428-
// there should be a
429-
// bucket count representing values between last bucket and
430-
// POSITIVE_INFINITY.
431-
histogramDataPoint.addExplicitBounds(
432-
isTimeBased ? countAtBucket.bucket(getBaseTimeUnit()) : countAtBucket.bucket());
433-
}
434-
histogramDataPoint.addBucketCounts((long) countAtBucket.count());
435-
}
436-
metricBuilder.setHistogram(io.opentelemetry.proto.metrics.v1.Histogram.newBuilder()
437-
.setAggregationTemporality(otlpAggregationTemporality)
438-
.addDataPoints(histogramDataPoint));
439-
return metricBuilder.build();
440-
}
441-
442-
return metricBuilder
443-
.setHistogram(io.opentelemetry.proto.metrics.v1.Histogram.newBuilder()
444-
.setAggregationTemporality(otlpAggregationTemporality)
445-
.addDataPoints(histogramDataPoint))
446-
.build();
447-
}
448-
449-
@Nullable
450-
private static ExponentialHistogramSnapShot getExponentialHistogramSnapShot(
451-
final HistogramSupport histogramSupport) {
452-
if (histogramSupport instanceof OtlpHistogramSupport) {
453-
return ((OtlpHistogramSupport) histogramSupport).getExponentialHistogramSnapShot();
454-
}
455-
456-
return null;
457-
}
458-
459-
// VisibleForTesting
460-
Metric writeFunctionTimer(FunctionTimer functionTimer) {
461-
return getMetricBuilder(functionTimer.getId())
462-
.setHistogram(io.opentelemetry.proto.metrics.v1.Histogram.newBuilder()
463-
.addDataPoints(HistogramDataPoint.newBuilder()
464-
.addAllAttributes(getTagsForId(functionTimer.getId()))
465-
.setStartTimeUnixNano(getStartTimeNanos((functionTimer)))
466-
.setTimeUnixNano(getTimeUnixNano())
467-
.setSum(functionTimer.totalTime(getBaseTimeUnit()))
468-
.setCount((long) functionTimer.count()))
469-
.setAggregationTemporality(otlpAggregationTemporality))
470-
.build();
471-
}
472-
473348
private boolean isCumulative() {
474349
return this.aggregationTemporality == AggregationTemporality.CUMULATIVE;
475350
}
@@ -516,14 +391,15 @@ static Histogram getHistogram(Clock clock, DistributionStatisticConfig distribut
516391

517392
static Histogram getHistogram(final Clock clock, final DistributionStatisticConfig distributionStatisticConfig,
518393
final OtlpConfig otlpConfig, @Nullable final TimeUnit baseTimeUnit) {
519-
// While publishing to OTLP, we export either Histogram datapoint (Explicit Bucket
394+
// While publishing to OTLP, we export either Histogram datapoint (Explicit
395+
// ExponentialBucket
520396
// or Exponential) / Summary
521397
// datapoint. So, we will make the histogram either of them and not both.
522398
// Though AbstractTimer/Distribution Summary prefers publishing percentiles,
523399
// exporting of histograms over percentiles is preferred in OTLP.
524400
if (distributionStatisticConfig.isPublishingHistogram()) {
525-
if (histogramFlavour(otlpConfig.histogramFlavour(),
526-
distributionStatisticConfig) == HistogramFlavour.BASE2_EXPONENTIAL_BUCKET_HISTOGRAM) {
401+
if (HistogramFlavour.BASE2_EXPONENTIAL_BUCKET_HISTOGRAM
402+
.equals(histogramFlavour(otlpConfig.histogramFlavour(), distributionStatisticConfig))) {
527403
Double minimumExpectedValue = distributionStatisticConfig.getMinimumExpectedValueAsDouble();
528404
if (minimumExpectedValue == null) {
529405
minimumExpectedValue = 0.0;

implementations/micrometer-registry-otlp/src/main/java/io/micrometer/registry/otlp/OtlpMetricConverter.java

Lines changed: 64 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
import io.micrometer.core.instrument.distribution.HistogramSupport;
2525
import io.micrometer.core.instrument.distribution.ValueAtPercentile;
2626
import io.micrometer.core.instrument.util.TimeUtils;
27+
import io.micrometer.registry.otlp.internal.ExponentialHistogramSnapShot;
2728
import io.opentelemetry.proto.common.v1.AnyValue;
2829
import io.opentelemetry.proto.common.v1.KeyValue;
2930
import io.opentelemetry.proto.metrics.v1.*;
@@ -122,16 +123,35 @@ private void writeHistogramSupport(HistogramSupport histogramSupport) {
122123
Iterable<KeyValue> tags = getKeyValuesForId(id);
123124
long startTimeNanos = getStartTimeNanos(histogramSupport);
124125
double total = isTimeBased ? histogramSnapshot.total(baseTimeUnit) : histogramSnapshot.total();
126+
double max = isTimeBased ? histogramSnapshot.max(baseTimeUnit) : histogramSnapshot.max();
125127
long count = histogramSnapshot.count();
126128

127129
// if percentiles configured, use summary
128130
if (histogramSnapshot.percentileValues().length != 0) {
129131
buildSummaryDataPoint(histogramSupport, tags, startTimeNanos, total, count, isTimeBased, histogramSnapshot);
132+
return;
133+
}
134+
135+
Optional<ExponentialHistogramSnapShot> exponentialHistogramSnapShot = getExponentialHistogramSnapShot(
136+
histogramSupport);
137+
if (exponentialHistogramSnapShot.isPresent()) {
138+
buildExponentialHistogramDataPoint(histogramSupport, tags, startTimeNanos, total, max, count,
139+
exponentialHistogramSnapShot.get());
130140
}
131141
else {
132-
buildHistogramDataPoint(histogramSupport, tags, startTimeNanos, total, count, isTimeBased,
142+
buildHistogramDataPoint(histogramSupport, tags, startTimeNanos, total, max, count, isTimeBased,
133143
histogramSnapshot);
134144
}
145+
146+
}
147+
148+
private static Optional<ExponentialHistogramSnapShot> getExponentialHistogramSnapShot(
149+
final HistogramSupport histogramSupport) {
150+
if (histogramSupport instanceof OtlpHistogramSupport) {
151+
return Optional.ofNullable(((OtlpHistogramSupport) histogramSupport).getExponentialHistogramSnapShot());
152+
}
153+
154+
return Optional.empty();
135155
}
136156

137157
private void writeFunctionTimer(FunctionTimer functionTimer) {
@@ -151,7 +171,8 @@ private boolean isTimeBasedMeter(Meter.Id id) {
151171
}
152172

153173
private void buildHistogramDataPoint(HistogramSupport histogramSupport, Iterable<KeyValue> tags,
154-
long startTimeNanos, double total, long count, boolean isTimeBased, HistogramSnapshot histogramSnapshot) {
174+
long startTimeNanos, double total, double max, long count, boolean isTimeBased,
175+
HistogramSnapshot histogramSnapshot) {
155176
Metric.Builder metricBuilder = getOrCreateMetricBuilder(histogramSupport.getId(), DataCase.HISTOGRAM);
156177
HistogramDataPoint.Builder histogramDataPoint = HistogramDataPoint.newBuilder()
157178
.addAllAttributes(tags)
@@ -161,7 +182,7 @@ private void buildHistogramDataPoint(HistogramSupport histogramSupport, Iterable
161182
.setCount(count);
162183

163184
if (isDelta()) {
164-
histogramDataPoint.setMax(isTimeBased ? histogramSnapshot.max(baseTimeUnit) : histogramSnapshot.max());
185+
histogramDataPoint.setMax(max);
165186
}
166187

167188
// if histogram enabled, add histogram buckets
@@ -180,6 +201,37 @@ private void buildHistogramDataPoint(HistogramSupport histogramSupport, Iterable
180201
setHistogramDataPoint(metricBuilder, histogramDataPoint.build());
181202
}
182203

204+
private void buildExponentialHistogramDataPoint(HistogramSupport histogramSupport, Iterable<KeyValue> tags,
205+
long startTimeNanos, double total, double max, long count,
206+
ExponentialHistogramSnapShot exponentialHistogramSnapShot) {
207+
Metric.Builder metricBuilder = getOrCreateMetricBuilder(histogramSupport.getId(),
208+
DataCase.EXPONENTIAL_HISTOGRAM);
209+
ExponentialHistogramDataPoint.Builder exponentialDataPoint = ExponentialHistogramDataPoint.newBuilder()
210+
.addAllAttributes(tags)
211+
.setStartTimeUnixNano(startTimeNanos)
212+
.setTimeUnixNano(getTimeUnixNano())
213+
.setCount(count)
214+
.setSum(total)
215+
.setScale(exponentialHistogramSnapShot.scale())
216+
.setZeroCount(exponentialHistogramSnapShot.zeroCount())
217+
.setZeroThreshold(exponentialHistogramSnapShot.zeroThreshold());
218+
219+
// Currently, micrometer doesn't support negative recordings hence we will only
220+
// add positive buckets.
221+
if (!exponentialHistogramSnapShot.positive().isEmpty()) {
222+
exponentialDataPoint.setPositive(ExponentialHistogramDataPoint.Buckets.newBuilder()
223+
.addAllBucketCounts(exponentialHistogramSnapShot.positive().bucketCounts())
224+
.setOffset(exponentialHistogramSnapShot.positive().offset())
225+
.build());
226+
}
227+
228+
if (isDelta()) {
229+
exponentialDataPoint.setMax(max);
230+
}
231+
232+
setExponentialHistogramDataPoint(metricBuilder, exponentialDataPoint.build());
233+
}
234+
183235
private void buildSummaryDataPoint(HistogramSupport histogramSupport, Iterable<KeyValue> tags, long startTimeNanos,
184236
double total, long count, boolean isTimeBased, HistogramSnapshot histogramSnapshot) {
185237
Metric.Builder metricBuilder = getOrCreateMetricBuilder(histogramSupport.getId(), DataCase.SUMMARY);
@@ -220,6 +272,15 @@ private void setHistogramDataPoint(Metric.Builder builder, HistogramDataPoint hi
220272
builder.getHistogramBuilder().addDataPoints(histogramDataPoint);
221273
}
222274

275+
private void setExponentialHistogramDataPoint(Metric.Builder builder,
276+
ExponentialHistogramDataPoint exponentialHistogramDataPoint) {
277+
if (!builder.hasExponentialHistogram()) {
278+
builder.setExponentialHistogram(
279+
ExponentialHistogram.newBuilder().setAggregationTemporality(otlpAggregationTemporality));
280+
}
281+
builder.getExponentialHistogramBuilder().addDataPoints(exponentialHistogramDataPoint);
282+
}
283+
223284
private void setSummaryDataPoint(Metric.Builder builder, SummaryDataPoint.Builder summaryDataPoint) {
224285
if (!builder.hasSummary()) {
225286
builder.setSummary(Summary.newBuilder());

implementations/micrometer-registry-otlp/src/main/java/io/micrometer/registry/otlp/internal/Base2ExponentialHistogram.java

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515
*/
1616
package io.micrometer.registry.otlp.internal;
1717

18+
import static io.micrometer.registry.otlp.internal.ExponentialHistogramSnapShot.ExponentialBucket.EMPTY_EXPONENTIAL_BUCKET;
19+
1820
import java.util.Arrays;
1921
import java.util.Collections;
2022
import java.util.List;
@@ -26,17 +28,24 @@
2628
import io.micrometer.core.instrument.distribution.Histogram;
2729
import io.micrometer.core.instrument.distribution.HistogramSnapshot;
2830
import io.micrometer.core.instrument.util.TimeUtils;
31+
import io.micrometer.registry.otlp.internal.ExponentialHistogramSnapShot.ExponentialBucket;
2932

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

@@ -115,8 +124,8 @@ public HistogramSnapshot takeSnapshot(final long count, final double total, fina
115124
ExponentialHistogramSnapShot getCurrentValuesSnapshot() {
116125
return (circularCountHolder.isEmpty() && zeroCount.longValue() == 0)
117126
? DefaultExponentialHistogramSnapShot.getEmptySnapshotForScale(scale)
118-
: new DefaultExponentialHistogramSnapShot(scale, getOffset(), zeroCount.longValue(), zeroThreshold,
119-
getBucketCounts());
127+
: new DefaultExponentialHistogramSnapShot(scale, zeroCount.longValue(), zeroThreshold,
128+
new ExponentialBucket(getOffset(), getBucketCounts()), EMPTY_EXPONENTIAL_BUCKET);
120129
}
121130

122131
/**

implementations/micrometer-registry-otlp/src/main/java/io/micrometer/registry/otlp/internal/CumulativeBase2ExponentialHistogram.java

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,14 @@
2121

2222
/**
2323
* A {@link Base2ExponentialHistogram} that tracks values cumulatively from first recorded
24-
* value.
24+
* value. *
25+
* <p>
26+
* * <strong> This is an internal class and might have breaking changes, external *
27+
* implementations SHOULD NOT rely on this implementation. </strong> *
28+
* </p>
2529
*
2630
* @author Lenin Jaganathan
27-
* @since 1.12.0
31+
* @since 1.14.0
2832
*/
2933
public class CumulativeBase2ExponentialHistogram extends Base2ExponentialHistogram {
3034

0 commit comments

Comments
 (0)