From 3c4b3dd3601296e224d4da1b15eee9a1674734a2 Mon Sep 17 00:00:00 2001 From: beanliu Date: Wed, 24 Feb 2021 13:55:33 +1100 Subject: [PATCH 1/4] add histogram related metric data types --- .../exporter/otlp/internal/MetricAdapter.java | 3 + .../exporter/prometheus/MetricAdapter.java | 7 ++ .../sdk/metrics/data/DoubleHistogramData.java | 34 +++++++ .../data/DoubleHistogramPointData.java | 93 +++++++++++++++++++ .../sdk/metrics/data/MetricData.java | 38 ++++++++ .../sdk/metrics/data/MetricDataType.java | 6 ++ .../sdk/metrics/data/MetricDataTest.java | 47 ++++++++++ 7 files changed, 228 insertions(+) create mode 100644 sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/data/DoubleHistogramData.java create mode 100644 sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/data/DoubleHistogramPointData.java diff --git a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/otlp/internal/MetricAdapter.java b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/otlp/internal/MetricAdapter.java index deb82a6e241..00217c900a2 100644 --- a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/otlp/internal/MetricAdapter.java +++ b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/otlp/internal/MetricAdapter.java @@ -149,6 +149,9 @@ static Metric toProtoMetric(MetricData metricData) { .addAllDataPoints(toDoubleDataPoints(doubleGaugeData.getPoints())) .build()); break; + case HISTOGRAM: + // no-op, will add in the following PRs + break; } return builder.build(); } diff --git a/exporters/prometheus/src/main/java/io/opentelemetry/exporter/prometheus/MetricAdapter.java b/exporters/prometheus/src/main/java/io/opentelemetry/exporter/prometheus/MetricAdapter.java index e04cb914a95..c4e99b00c33 100644 --- a/exporters/prometheus/src/main/java/io/opentelemetry/exporter/prometheus/MetricAdapter.java +++ b/exporters/prometheus/src/main/java/io/opentelemetry/exporter/prometheus/MetricAdapter.java @@ -85,6 +85,8 @@ static Collector.Type toMetricFamilyType(MetricData metricData) { return Collector.Type.GAUGE; case SUMMARY: return Collector.Type.SUMMARY; + case HISTOGRAM: + return Collector.Type.HISTOGRAM; } return Collector.Type.UNKNOWN; } @@ -122,6 +124,9 @@ static List toSamples( 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 @@ private static Collection getPoints(MetricData metricData) return metricData.getLongSumData().getPoints(); case SUMMARY: return metricData.getDoubleSummaryData().getPoints(); + case HISTOGRAM: + return metricData.getDoubleHistogramData().getPoints(); } return Collections.emptyList(); } diff --git a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/data/DoubleHistogramData.java b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/data/DoubleHistogramData.java new file mode 100644 index 00000000000..a5f90422faf --- /dev/null +++ b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/data/DoubleHistogramData.java @@ -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 { + DoubleHistogramData() {} + + public static DoubleHistogramData create( + AggregationTemporality temporality, Collection points) { + return new AutoValue_DoubleHistogramData(temporality, points); + } + + /** + * Returns the {@code AggregationTemporality} of this metric, + * + *

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 getPoints(); +} diff --git a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/data/DoubleHistogramPointData.java b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/data/DoubleHistogramPointData.java new file mode 100644 index 00000000000..4b6d16f8c3e --- /dev/null +++ b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/data/DoubleHistogramPointData.java @@ -0,0 +1,93 @@ +/* + * 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 { + /** + * Functional interface for consuming bucket boundaries and counts as a sequence of pair values. + */ + public interface BucketConsumer { + void accept(double upperBound, long count); + } + + /** + * Creates a DoubleHistogramPointData. + * + * @return a DoubleHistogramPointData. + */ + public static DoubleHistogramPointData create( + long startEpochNanos, + long epochNanos, + Labels labels, + double sum, + long count, + List boundaries, + List counts) { + return new AutoValue_DoubleHistogramPointData( + startEpochNanos, + epochNanos, + labels, + sum, + count, + 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. do not mutate the returned + * object. + */ + public abstract List getBoundaries(); + + /** + * The counts in each bucket. + * + * @return the read-only counts in each bucket. do not mutate the returned object. + */ + public abstract List getCounts(); + + /** Iterates over all the bucket boundaries and counts in this histogram. */ + public void forEach(BucketConsumer action) { + List boundaries = getBoundaries(); + List counts = getCounts(); + for (int i = 0; i < boundaries.size(); ++i) { + action.accept(boundaries.get(i), counts.get(i)); + } + action.accept(Double.POSITIVE_INFINITY, counts.get(boundaries.size())); + } +} diff --git a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/data/MetricData.java b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/data/MetricData.java index d7e2939635a..61df82f5db5 100644 --- a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/data/MetricData.java +++ b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/data/MetricData.java @@ -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 static MetricData createDoubleSummary( 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 final DoubleSummaryData getDoubleSummaryData() { } 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; + } } diff --git a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/data/MetricDataType.java b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/data/MetricDataType.java index 50adc159fbd..0749807848f 100644 --- a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/data/MetricDataType.java +++ b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/data/MetricDataType.java @@ -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, } diff --git a/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/data/MetricDataTest.java b/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/data/MetricDataTest.java index 01eae936c1e..e89013a2f30 100644 --- a/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/data/MetricDataTest.java +++ b/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/data/MetricDataTest.java @@ -7,11 +7,14 @@ 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.ArrayList; import java.util.Arrays; import java.util.Collections; +import java.util.List; import java.util.concurrent.TimeUnit; import org.junit.jupiter.api.Test; @@ -40,6 +43,15 @@ 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, + LONG_VALUE, + ImmutableList.of(1.0), + ImmutableList.of(1L, 1L)); @Test void metricData_Getters() { @@ -146,6 +158,39 @@ void metricData_SummaryPoints() { 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(LONG_VALUE); + 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)); + + List boundaries = new ArrayList<>(); + List counts = new ArrayList<>(); + HISTOGRAM_POINT.forEach( + (b, c) -> { + boundaries.add(b); + counts.add(c); + }); + assertThat(boundaries).isEqualTo(Arrays.asList(1.0, Double.POSITIVE_INFINITY)); + assertThat(counts).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); + } + @Test void metricData_GetDefault() { MetricData metricData = @@ -160,6 +205,7 @@ void metricData_GetDefault() { 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 +220,7 @@ void metricData_GetDefault() { 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(); } } From 38a75579d814a397bf2a4eaf9a415d1309307002 Mon Sep 17 00:00:00 2001 From: beanliu Date: Thu, 25 Feb 2021 09:39:11 +1100 Subject: [PATCH 2/4] update doc of histogram boundaries to make it compatible with latest change of ot-proto --- .../sdk/metrics/data/DoubleHistogramPointData.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/data/DoubleHistogramPointData.java b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/data/DoubleHistogramPointData.java index 4b6d16f8c3e..fb707319a11 100644 --- a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/data/DoubleHistogramPointData.java +++ b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/data/DoubleHistogramPointData.java @@ -67,7 +67,7 @@ public static DoubleHistogramPointData create( /** * 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]. + * counts: (-inf, x], (x, y], (y, z], (z, +inf). * * @return the read-only bucket boundaries in increasing order. do not mutate the returned * object. From 596c50bc20e3edda377765ea5c96ea489705962f Mon Sep 17 00:00:00 2001 From: beanliu Date: Thu, 25 Feb 2021 09:40:56 +1100 Subject: [PATCH 3/4] remove unnecessary helper --- .../metrics/data/DoubleHistogramPointData.java | 17 ----------------- .../sdk/metrics/data/MetricDataTest.java | 12 ------------ 2 files changed, 29 deletions(-) diff --git a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/data/DoubleHistogramPointData.java b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/data/DoubleHistogramPointData.java index fb707319a11..acccded2b5b 100644 --- a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/data/DoubleHistogramPointData.java +++ b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/data/DoubleHistogramPointData.java @@ -19,13 +19,6 @@ @Immutable @AutoValue public abstract class DoubleHistogramPointData implements PointData { - /** - * Functional interface for consuming bucket boundaries and counts as a sequence of pair values. - */ - public interface BucketConsumer { - void accept(double upperBound, long count); - } - /** * Creates a DoubleHistogramPointData. * @@ -80,14 +73,4 @@ public static DoubleHistogramPointData create( * @return the read-only counts in each bucket. do not mutate the returned object. */ public abstract List getCounts(); - - /** Iterates over all the bucket boundaries and counts in this histogram. */ - public void forEach(BucketConsumer action) { - List boundaries = getBoundaries(); - List counts = getCounts(); - for (int i = 0; i < boundaries.size(); ++i) { - action.accept(boundaries.get(i), counts.get(i)); - } - action.accept(Double.POSITIVE_INFINITY, counts.get(boundaries.size())); - } } diff --git a/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/data/MetricDataTest.java b/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/data/MetricDataTest.java index e89013a2f30..a06a8c32ec7 100644 --- a/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/data/MetricDataTest.java +++ b/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/data/MetricDataTest.java @@ -11,10 +11,8 @@ import io.opentelemetry.api.metrics.common.Labels; import io.opentelemetry.sdk.common.InstrumentationLibraryInfo; import io.opentelemetry.sdk.resources.Resource; -import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; -import java.util.List; import java.util.concurrent.TimeUnit; import org.junit.jupiter.api.Test; @@ -169,16 +167,6 @@ void metricData_HistogramPoints() { assertThat(HISTOGRAM_POINT.getBoundaries()).isEqualTo(ImmutableList.of(1.0)); assertThat(HISTOGRAM_POINT.getCounts()).isEqualTo(ImmutableList.of(1L, 1L)); - List boundaries = new ArrayList<>(); - List counts = new ArrayList<>(); - HISTOGRAM_POINT.forEach( - (b, c) -> { - boundaries.add(b); - counts.add(c); - }); - assertThat(boundaries).isEqualTo(Arrays.asList(1.0, Double.POSITIVE_INFINITY)); - assertThat(counts).isEqualTo(ImmutableList.of(1L, 1L)); - MetricData metricData = MetricData.createDoubleHistogram( Resource.empty(), From 52de0bec6d45e5ce08212ed11eac6787df743fa0 Mon Sep 17 00:00:00 2001 From: beanliu Date: Thu, 25 Feb 2021 10:10:22 +1100 Subject: [PATCH 4/4] simplify the create interface, add doc and validations --- .../data/DoubleHistogramPointData.java | 35 +++++++++++++++++-- .../sdk/metrics/data/MetricDataTest.java | 30 ++++++++++++++-- 2 files changed, 60 insertions(+), 5 deletions(-) diff --git a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/data/DoubleHistogramPointData.java b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/data/DoubleHistogramPointData.java index acccded2b5b..22e5e13461b 100644 --- a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/data/DoubleHistogramPointData.java +++ b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/data/DoubleHistogramPointData.java @@ -20,24 +20,44 @@ @AutoValue public abstract class DoubleHistogramPointData implements PointData { /** - * Creates a DoubleHistogramPointData. + * 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, - long count, List boundaries, List 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, - count, + totalCount, Collections.unmodifiableList(new ArrayList<>(boundaries)), Collections.unmodifiableList(new ArrayList<>(counts))); } @@ -73,4 +93,13 @@ public static DoubleHistogramPointData create( * @return the read-only counts in each bucket. do not mutate the returned object. */ public abstract List getCounts(); + + private static boolean isStrictlyIncreasing(List xs) { + for (int i = 0; i < xs.size() - 1; i++) { + if (xs.get(i).compareTo(xs.get(i + 1)) >= 0) { + return false; + } + } + return true; + } } diff --git a/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/data/MetricDataTest.java b/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/data/MetricDataTest.java index a06a8c32ec7..c72fa92d25b 100644 --- a/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/data/MetricDataTest.java +++ b/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/data/MetricDataTest.java @@ -14,6 +14,7 @@ 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}. */ @@ -47,7 +48,6 @@ class MetricDataTest { EPOCH_NANOS, Labels.of("key", "value"), DOUBLE_VALUE, - LONG_VALUE, ImmutableList.of(1.0), ImmutableList.of(1L, 1L)); @@ -162,7 +162,7 @@ void metricData_HistogramPoints() { 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(LONG_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)); @@ -177,6 +177,32 @@ void metricData_HistogramPoints() { 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