Histogram Aggregation - core SDK - data (#2923)
* add histogram related metric data types * update doc of histogram boundaries to make it compatible with latest change of ot-proto * remove unnecessary helper * simplify the create interface, add doc and validations
This commit is contained in:
parent
1102efae1d
commit
f1c38ef616
|
|
@ -149,6 +149,9 @@ public final class MetricAdapter {
|
|||
.addAllDataPoints(toDoubleDataPoints(doubleGaugeData.getPoints()))
|
||||
.build());
|
||||
break;
|
||||
case HISTOGRAM:
|
||||
// no-op, will add in the following PRs
|
||||
break;
|
||||
}
|
||||
return builder.build();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -85,6 +85,8 @@ final class MetricAdapter {
|
|||
return Collector.Type.GAUGE;
|
||||
case SUMMARY:
|
||||
return Collector.Type.SUMMARY;
|
||||
case HISTOGRAM:
|
||||
return Collector.Type.HISTOGRAM;
|
||||
}
|
||||
return Collector.Type.UNKNOWN;
|
||||
}
|
||||
|
|
@ -122,6 +124,9 @@ final class MetricAdapter {
|
|||
addSummarySamples(
|
||||
(DoubleSummaryPointData) pointData, name, labelNames, labelValues, samples);
|
||||
break;
|
||||
case HISTOGRAM:
|
||||
// no-op, will add in the following PRs
|
||||
break;
|
||||
}
|
||||
}
|
||||
return samples;
|
||||
|
|
@ -189,6 +194,8 @@ final class MetricAdapter {
|
|||
return metricData.getLongSumData().getPoints();
|
||||
case SUMMARY:
|
||||
return metricData.getDoubleSummaryData().getPoints();
|
||||
case HISTOGRAM:
|
||||
return metricData.getDoubleHistogramData().getPoints();
|
||||
}
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
* Copyright The OpenTelemetry Authors
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package io.opentelemetry.sdk.metrics.data;
|
||||
|
||||
import com.google.auto.value.AutoValue;
|
||||
import java.util.Collection;
|
||||
import javax.annotation.concurrent.Immutable;
|
||||
|
||||
@Immutable
|
||||
@AutoValue
|
||||
public abstract class DoubleHistogramData implements Data<DoubleHistogramPointData> {
|
||||
DoubleHistogramData() {}
|
||||
|
||||
public static DoubleHistogramData create(
|
||||
AggregationTemporality temporality, Collection<DoubleHistogramPointData> points) {
|
||||
return new AutoValue_DoubleHistogramData(temporality, points);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@code AggregationTemporality} of this metric,
|
||||
*
|
||||
* <p>AggregationTemporality describes if the aggregator reports delta changes since last report
|
||||
* time, or cumulative changes since a fixed start time.
|
||||
*
|
||||
* @return the {@code AggregationTemporality} of this metric
|
||||
*/
|
||||
public abstract AggregationTemporality getAggregationTemporality();
|
||||
|
||||
@Override
|
||||
public abstract Collection<DoubleHistogramPointData> getPoints();
|
||||
}
|
||||
|
|
@ -0,0 +1,105 @@
|
|||
/*
|
||||
* Copyright The OpenTelemetry Authors
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package io.opentelemetry.sdk.metrics.data;
|
||||
|
||||
import com.google.auto.value.AutoValue;
|
||||
import io.opentelemetry.api.metrics.common.Labels;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import javax.annotation.concurrent.Immutable;
|
||||
|
||||
/**
|
||||
* DoubleHistogramPointData represents an approximate representation of the distribution of
|
||||
* measurements.
|
||||
*/
|
||||
@Immutable
|
||||
@AutoValue
|
||||
public abstract class DoubleHistogramPointData implements PointData {
|
||||
/**
|
||||
* Creates a DoubleHistogramPointData. For a Histogram with N defined boundaries, there should be
|
||||
* N+1 counts.
|
||||
*
|
||||
* @return a DoubleHistogramPointData.
|
||||
* @throws IllegalArgumentException if the given boundaries/counts were invalid
|
||||
*/
|
||||
public static DoubleHistogramPointData create(
|
||||
long startEpochNanos,
|
||||
long epochNanos,
|
||||
Labels labels,
|
||||
double sum,
|
||||
List<Double> boundaries,
|
||||
List<Long> counts) {
|
||||
if (counts.size() != boundaries.size() + 1) {
|
||||
throw new IllegalArgumentException(
|
||||
"invalid counts: size should be "
|
||||
+ (boundaries.size() + 1)
|
||||
+ " instead of "
|
||||
+ counts.size());
|
||||
}
|
||||
if (!isStrictlyIncreasing(boundaries)) {
|
||||
throw new IllegalArgumentException("invalid boundaries: " + boundaries);
|
||||
}
|
||||
if (!boundaries.isEmpty()
|
||||
&& (boundaries.get(0).isInfinite() || boundaries.get(boundaries.size() - 1).isInfinite())) {
|
||||
throw new IllegalArgumentException("invalid boundaries: contains explicit +/-Inf");
|
||||
}
|
||||
|
||||
long totalCount = 0;
|
||||
for (long c : counts) {
|
||||
totalCount += c;
|
||||
}
|
||||
return new AutoValue_DoubleHistogramPointData(
|
||||
startEpochNanos,
|
||||
epochNanos,
|
||||
labels,
|
||||
sum,
|
||||
totalCount,
|
||||
Collections.unmodifiableList(new ArrayList<>(boundaries)),
|
||||
Collections.unmodifiableList(new ArrayList<>(counts)));
|
||||
}
|
||||
|
||||
DoubleHistogramPointData() {}
|
||||
|
||||
/**
|
||||
* The sum of all measurements recorded.
|
||||
*
|
||||
* @return the sum of recorded measurements.
|
||||
*/
|
||||
public abstract double getSum();
|
||||
|
||||
/**
|
||||
* The number of measurements taken.
|
||||
*
|
||||
* @return the count of recorded measurements.
|
||||
*/
|
||||
public abstract long getCount();
|
||||
|
||||
/**
|
||||
* The bucket boundaries. For a Histogram with N defined boundaries, e.g, [x, y, z]. There are N+1
|
||||
* counts: (-inf, x], (x, y], (y, z], (z, +inf).
|
||||
*
|
||||
* @return the read-only bucket boundaries in increasing order. <b>do not mutate</b> the returned
|
||||
* object.
|
||||
*/
|
||||
public abstract List<Double> getBoundaries();
|
||||
|
||||
/**
|
||||
* The counts in each bucket.
|
||||
*
|
||||
* @return the read-only counts in each bucket. <b>do not mutate</b> the returned object.
|
||||
*/
|
||||
public abstract List<Long> getCounts();
|
||||
|
||||
private static boolean isStrictlyIncreasing(List<Double> xs) {
|
||||
for (int i = 0; i < xs.size() - 1; i++) {
|
||||
if (xs.get(i).compareTo(xs.get(i + 1)) >= 0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
@ -29,6 +29,8 @@ public abstract class MetricData {
|
|||
/* isMonotonic= */ false, AggregationTemporality.CUMULATIVE, Collections.emptyList());
|
||||
private static final DoubleSummaryData DEFAULT_DOUBLE_SUMMARY_DATA =
|
||||
DoubleSummaryData.create(Collections.emptyList());
|
||||
private static final DoubleHistogramData DEFAULT_DOUBLE_HISTOGRAM_DATA =
|
||||
DoubleHistogramData.create(AggregationTemporality.CUMULATIVE, Collections.emptyList());
|
||||
|
||||
/**
|
||||
* Returns a new MetricData wih a {@link MetricDataType#DOUBLE_GAUGE} type.
|
||||
|
|
@ -140,6 +142,28 @@ public abstract class MetricData {
|
|||
data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new MetricData with a {@link MetricDataType#HISTOGRAM} type.
|
||||
*
|
||||
* @return a new MetricData wih a {@link MetricDataType#HISTOGRAM} type.
|
||||
*/
|
||||
public static MetricData createDoubleHistogram(
|
||||
Resource resource,
|
||||
InstrumentationLibraryInfo instrumentationLibraryInfo,
|
||||
String name,
|
||||
String description,
|
||||
String unit,
|
||||
DoubleHistogramData data) {
|
||||
return new AutoValue_MetricData(
|
||||
resource,
|
||||
instrumentationLibraryInfo,
|
||||
name,
|
||||
description,
|
||||
unit,
|
||||
MetricDataType.HISTOGRAM,
|
||||
data);
|
||||
}
|
||||
|
||||
MetricData() {}
|
||||
|
||||
/**
|
||||
|
|
@ -265,4 +289,18 @@ public abstract class MetricData {
|
|||
}
|
||||
return DEFAULT_DOUBLE_SUMMARY_DATA;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@code DoubleHistogramData} if type is {@link MetricDataType#HISTOGRAM}, otherwise
|
||||
* a default empty data.
|
||||
*
|
||||
* @return the {@code DoubleHistogramData} if type is {@link MetricDataType#HISTOGRAM}, otherwise
|
||||
* a default empty data.
|
||||
*/
|
||||
public final DoubleHistogramData getDoubleHistogramData() {
|
||||
if (getType() == MetricDataType.HISTOGRAM) {
|
||||
return (DoubleHistogramData) getData();
|
||||
}
|
||||
return DEFAULT_DOUBLE_HISTOGRAM_DATA;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -30,4 +30,10 @@ public enum MetricDataType {
|
|||
* value recorded, the sum of all measurements and the total number of measurements recorded.
|
||||
*/
|
||||
SUMMARY,
|
||||
|
||||
/**
|
||||
* A Histogram represents an approximate representation of the distribution of measurements
|
||||
* recorded.
|
||||
*/
|
||||
HISTOGRAM,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,12 +7,14 @@ package io.opentelemetry.sdk.metrics.data;
|
|||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import io.opentelemetry.api.metrics.common.Labels;
|
||||
import io.opentelemetry.sdk.common.InstrumentationLibraryInfo;
|
||||
import io.opentelemetry.sdk.resources.Resource;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
/** Unit tests for {@link io.opentelemetry.sdk.metrics.data.MetricData}. */
|
||||
|
|
@ -40,6 +42,14 @@ class MetricDataTest {
|
|||
Arrays.asList(
|
||||
ValueAtPercentile.create(0.0, DOUBLE_VALUE),
|
||||
ValueAtPercentile.create(100, DOUBLE_VALUE)));
|
||||
private static final DoubleHistogramPointData HISTOGRAM_POINT =
|
||||
DoubleHistogramPointData.create(
|
||||
START_EPOCH_NANOS,
|
||||
EPOCH_NANOS,
|
||||
Labels.of("key", "value"),
|
||||
DOUBLE_VALUE,
|
||||
ImmutableList.of(1.0),
|
||||
ImmutableList.of(1L, 1L));
|
||||
|
||||
@Test
|
||||
void metricData_Getters() {
|
||||
|
|
@ -146,6 +156,55 @@ class MetricDataTest {
|
|||
assertThat(metricData.getDoubleSummaryData().getPoints()).containsExactly(SUMMARY_POINT);
|
||||
}
|
||||
|
||||
@Test
|
||||
void metricData_HistogramPoints() {
|
||||
assertThat(HISTOGRAM_POINT.getStartEpochNanos()).isEqualTo(START_EPOCH_NANOS);
|
||||
assertThat(HISTOGRAM_POINT.getEpochNanos()).isEqualTo(EPOCH_NANOS);
|
||||
assertThat(HISTOGRAM_POINT.getLabels().size()).isEqualTo(1);
|
||||
assertThat(HISTOGRAM_POINT.getLabels().get("key")).isEqualTo("value");
|
||||
assertThat(HISTOGRAM_POINT.getCount()).isEqualTo(2L);
|
||||
assertThat(HISTOGRAM_POINT.getSum()).isEqualTo(DOUBLE_VALUE);
|
||||
assertThat(HISTOGRAM_POINT.getBoundaries()).isEqualTo(ImmutableList.of(1.0));
|
||||
assertThat(HISTOGRAM_POINT.getCounts()).isEqualTo(ImmutableList.of(1L, 1L));
|
||||
|
||||
MetricData metricData =
|
||||
MetricData.createDoubleHistogram(
|
||||
Resource.empty(),
|
||||
InstrumentationLibraryInfo.empty(),
|
||||
"metric_name",
|
||||
"metric_description",
|
||||
"ms",
|
||||
DoubleHistogramData.create(
|
||||
AggregationTemporality.DELTA, Collections.singleton(HISTOGRAM_POINT)));
|
||||
assertThat(metricData.getDoubleHistogramData().getPoints()).containsExactly(HISTOGRAM_POINT);
|
||||
|
||||
Assertions.assertThrows(
|
||||
IllegalArgumentException.class,
|
||||
() ->
|
||||
DoubleHistogramPointData.create(
|
||||
0, 0, Labels.empty(), 0.0, ImmutableList.of(), ImmutableList.of()));
|
||||
Assertions.assertThrows(
|
||||
IllegalArgumentException.class,
|
||||
() ->
|
||||
DoubleHistogramPointData.create(
|
||||
0,
|
||||
0,
|
||||
Labels.empty(),
|
||||
0.0,
|
||||
ImmutableList.of(1.0, 1.0),
|
||||
ImmutableList.of(0L, 0L, 0L)));
|
||||
Assertions.assertThrows(
|
||||
IllegalArgumentException.class,
|
||||
() ->
|
||||
DoubleHistogramPointData.create(
|
||||
0,
|
||||
0,
|
||||
Labels.empty(),
|
||||
0.0,
|
||||
ImmutableList.of(Double.NEGATIVE_INFINITY),
|
||||
ImmutableList.of(0L, 0L)));
|
||||
}
|
||||
|
||||
@Test
|
||||
void metricData_GetDefault() {
|
||||
MetricData metricData =
|
||||
|
|
@ -160,6 +219,7 @@ class MetricDataTest {
|
|||
assertThat(metricData.getLongGaugeData().getPoints()).isEmpty();
|
||||
assertThat(metricData.getDoubleSumData().getPoints()).isEmpty();
|
||||
assertThat(metricData.getLongGaugeData().getPoints()).isEmpty();
|
||||
assertThat(metricData.getDoubleHistogramData().getPoints()).isEmpty();
|
||||
assertThat(metricData.getDoubleSummaryData().getPoints()).containsExactly(SUMMARY_POINT);
|
||||
|
||||
metricData =
|
||||
|
|
@ -174,6 +234,7 @@ class MetricDataTest {
|
|||
assertThat(metricData.getLongGaugeData().getPoints()).isEmpty();
|
||||
assertThat(metricData.getDoubleSumData().getPoints()).isEmpty();
|
||||
assertThat(metricData.getLongGaugeData().getPoints()).isEmpty();
|
||||
assertThat(metricData.getDoubleHistogramData().getPoints()).isEmpty();
|
||||
assertThat(metricData.getDoubleSummaryData().getPoints()).isEmpty();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue