From 90edbd5a8a0ff10d7658bd78beae9434aee8cdbe Mon Sep 17 00:00:00 2001 From: Bogdan Drutu Date: Tue, 2 Oct 2018 17:48:35 -0400 Subject: Mode classes for metrics data model in the exporter package. (#1480) * Mode classes for metrics data model in the exporter package. Consistent with trace. * Fix test class coments. --- .../java/io/opencensus/metrics/Distribution.java | 280 --------------------- .../main/java/io/opencensus/metrics/Metric.java | 104 -------- .../io/opencensus/metrics/MetricDescriptor.java | 172 ------------- .../java/io/opencensus/metrics/MetricProducer.java | 41 --- .../java/io/opencensus/metrics/MetricRegistry.java | 2 +- api/src/main/java/io/opencensus/metrics/Point.java | 63 ----- .../main/java/io/opencensus/metrics/Summary.java | 187 -------------- .../java/io/opencensus/metrics/TimeSeries.java | 94 ------- api/src/main/java/io/opencensus/metrics/Value.java | 246 ------------------ .../io/opencensus/metrics/export/Distribution.java | 280 +++++++++++++++++++++ .../java/io/opencensus/metrics/export/Metric.java | 104 ++++++++ .../metrics/export/MetricDescriptor.java | 173 +++++++++++++ .../opencensus/metrics/export/MetricProducer.java | 40 +++ .../metrics/export/MetricProducerManager.java | 1 - .../java/io/opencensus/metrics/export/Point.java | 63 +++++ .../java/io/opencensus/metrics/export/Summary.java | 187 ++++++++++++++ .../io/opencensus/metrics/export/TimeSeries.java | 96 +++++++ .../java/io/opencensus/metrics/export/Value.java | 246 ++++++++++++++++++ .../io/opencensus/metrics/DistributionTest.java | 227 ----------------- .../opencensus/metrics/MetricDescriptorTest.java | 102 -------- .../java/io/opencensus/metrics/MetricTest.java | 116 --------- .../test/java/io/opencensus/metrics/PointTest.java | 68 ----- .../java/io/opencensus/metrics/SummaryTest.java | 189 -------------- .../java/io/opencensus/metrics/TimeSeriesTest.java | 116 --------- .../test/java/io/opencensus/metrics/ValueTest.java | 155 ------------ .../metrics/export/DistributionTest.java | 227 +++++++++++++++++ .../metrics/export/MetricDescriptorTest.java | 103 ++++++++ .../metrics/export/MetricProducerManagerTest.java | 1 - .../io/opencensus/metrics/export/MetricTest.java | 118 +++++++++ .../io/opencensus/metrics/export/PointTest.java | 68 +++++ .../io/opencensus/metrics/export/SummaryTest.java | 189 ++++++++++++++ .../opencensus/metrics/export/TimeSeriesTest.java | 117 +++++++++ .../io/opencensus/metrics/export/ValueTest.java | 155 ++++++++++++ 33 files changed, 2167 insertions(+), 2163 deletions(-) delete mode 100644 api/src/main/java/io/opencensus/metrics/Distribution.java delete mode 100644 api/src/main/java/io/opencensus/metrics/Metric.java delete mode 100644 api/src/main/java/io/opencensus/metrics/MetricDescriptor.java delete mode 100644 api/src/main/java/io/opencensus/metrics/MetricProducer.java delete mode 100644 api/src/main/java/io/opencensus/metrics/Point.java delete mode 100644 api/src/main/java/io/opencensus/metrics/Summary.java delete mode 100644 api/src/main/java/io/opencensus/metrics/TimeSeries.java delete mode 100644 api/src/main/java/io/opencensus/metrics/Value.java create mode 100644 api/src/main/java/io/opencensus/metrics/export/Distribution.java create mode 100644 api/src/main/java/io/opencensus/metrics/export/Metric.java create mode 100644 api/src/main/java/io/opencensus/metrics/export/MetricDescriptor.java create mode 100644 api/src/main/java/io/opencensus/metrics/export/MetricProducer.java create mode 100644 api/src/main/java/io/opencensus/metrics/export/Point.java create mode 100644 api/src/main/java/io/opencensus/metrics/export/Summary.java create mode 100644 api/src/main/java/io/opencensus/metrics/export/TimeSeries.java create mode 100644 api/src/main/java/io/opencensus/metrics/export/Value.java delete mode 100644 api/src/test/java/io/opencensus/metrics/DistributionTest.java delete mode 100644 api/src/test/java/io/opencensus/metrics/MetricDescriptorTest.java delete mode 100644 api/src/test/java/io/opencensus/metrics/MetricTest.java delete mode 100644 api/src/test/java/io/opencensus/metrics/PointTest.java delete mode 100644 api/src/test/java/io/opencensus/metrics/SummaryTest.java delete mode 100644 api/src/test/java/io/opencensus/metrics/TimeSeriesTest.java delete mode 100644 api/src/test/java/io/opencensus/metrics/ValueTest.java create mode 100644 api/src/test/java/io/opencensus/metrics/export/DistributionTest.java create mode 100644 api/src/test/java/io/opencensus/metrics/export/MetricDescriptorTest.java create mode 100644 api/src/test/java/io/opencensus/metrics/export/MetricTest.java create mode 100644 api/src/test/java/io/opencensus/metrics/export/PointTest.java create mode 100644 api/src/test/java/io/opencensus/metrics/export/SummaryTest.java create mode 100644 api/src/test/java/io/opencensus/metrics/export/TimeSeriesTest.java create mode 100644 api/src/test/java/io/opencensus/metrics/export/ValueTest.java (limited to 'api') diff --git a/api/src/main/java/io/opencensus/metrics/Distribution.java b/api/src/main/java/io/opencensus/metrics/Distribution.java deleted file mode 100644 index 9294b838..00000000 --- a/api/src/main/java/io/opencensus/metrics/Distribution.java +++ /dev/null @@ -1,280 +0,0 @@ -/* - * Copyright 2018, OpenCensus Authors - * - * 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 - * - * http://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.opencensus.metrics; - -import com.google.auto.value.AutoValue; -import io.opencensus.common.ExperimentalApi; -import io.opencensus.common.Timestamp; -import io.opencensus.internal.Utils; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; -import javax.annotation.Nullable; -import javax.annotation.concurrent.Immutable; - -/** - * {@link Distribution} contains summary statistics for a population of values. It optionally - * contains a histogram representing the distribution of those values across a set of buckets. - * - * @since 0.17 - */ -@ExperimentalApi -@AutoValue -@Immutable -public abstract class Distribution { - - Distribution() {} - - /** - * Creates a {@link Distribution}. - * - * @param count the count of the population values. - * @param sum the sum of the population values. - * @param sumOfSquaredDeviations the sum of squared deviations of the population values. - * @param bucketBoundaries bucket boundaries of a histogram. - * @param buckets {@link Bucket}s of a histogram. - * @return a {@code Distribution}. - * @since 0.17 - */ - public static Distribution create( - long count, - double sum, - double sumOfSquaredDeviations, - List bucketBoundaries, - List buckets) { - Utils.checkArgument(count >= 0, "count should be non-negative."); - Utils.checkArgument( - sumOfSquaredDeviations >= 0, "sum of squared deviations should be non-negative."); - if (count == 0) { - Utils.checkArgument(sum == 0, "sum should be 0 if count is 0."); - Utils.checkArgument( - sumOfSquaredDeviations == 0, "sum of squared deviations should be 0 if count is 0."); - } - return new AutoValue_Distribution( - count, - sum, - sumOfSquaredDeviations, - copyBucketBounds(bucketBoundaries), - copyBucketCount(buckets)); - } - - private static List copyBucketBounds(List bucketBoundaries) { - Utils.checkNotNull(bucketBoundaries, "bucketBoundaries list should not be null."); - List bucketBoundariesCopy = new ArrayList(bucketBoundaries); // Deep copy. - // Check if sorted. - if (bucketBoundariesCopy.size() > 1) { - double lower = bucketBoundariesCopy.get(0); - for (int i = 1; i < bucketBoundariesCopy.size(); i++) { - double next = bucketBoundariesCopy.get(i); - Utils.checkArgument(lower < next, "bucket boundaries not sorted."); - lower = next; - } - } - return Collections.unmodifiableList(bucketBoundariesCopy); - } - - private static List copyBucketCount(List buckets) { - Utils.checkNotNull(buckets, "bucket list should not be null."); - List bucketsCopy = new ArrayList(buckets); - for (Bucket bucket : bucketsCopy) { - Utils.checkNotNull(bucket, "bucket should not be null."); - } - return Collections.unmodifiableList(bucketsCopy); - } - - /** - * Returns the aggregated count. - * - * @return the aggregated count. - * @since 0.17 - */ - public abstract long getCount(); - - /** - * Returns the aggregated sum. - * - * @return the aggregated sum. - * @since 0.17 - */ - public abstract double getSum(); - - /** - * Returns the aggregated sum of squared deviations. - * - *

The sum of squared deviations from the mean of the values in the population. For values x_i - * this is: - * - *

Sum[i=1..n]((x_i - mean)^2) - * - *

If count is zero then this field must be zero. - * - * @return the aggregated sum of squared deviations. - * @since 0.17 - */ - public abstract double getSumOfSquaredDeviations(); - - /** - * Returns the bucket boundaries of this distribution. - * - *

The bucket boundaries for that histogram are described by bucket_bounds. This defines - * size(bucket_bounds) + 1 (= N) buckets. The boundaries for bucket index i are: - * - *

    - *
  • {@code (-infinity, bucket_bounds[i]) for i == 0} - *
  • {@code [bucket_bounds[i-1], bucket_bounds[i]) for 0 < i < N-2} - *
  • {@code [bucket_bounds[i-1], +infinity) for i == N-1} - *
- * - *

i.e. an underflow bucket (number 0), zero or more finite buckets (1 through N - 2, and an - * overflow bucket (N - 1), with inclusive lower bounds and exclusive upper bounds. - * - *

If bucket_bounds has no elements (zero size), then there is no histogram associated with the - * Distribution. If bucket_bounds has only one element, there are no finite buckets, and that - * single element is the common boundary of the overflow and underflow buckets. The values must be - * monotonically increasing. - * - * @return the bucket boundaries of this distribution. - * @since 0.17 - */ - public abstract List getBucketBoundaries(); - - /** - * Returns the aggregated histogram {@link Bucket}s. - * - * @return the aggregated histogram buckets. - * @since 0.17 - */ - public abstract List getBuckets(); - - /** - * The histogram bucket of the population values. - * - * @since 0.17 - */ - @AutoValue - @Immutable - public abstract static class Bucket { - - Bucket() {} - - /** - * Creates a {@link Bucket}. - * - * @param count the number of values in each bucket of the histogram. - * @return a {@code Bucket}. - * @since 0.17 - */ - public static Bucket create(long count) { - Utils.checkArgument(count >= 0, "bucket count should be non-negative."); - return new AutoValue_Distribution_Bucket(count, null); - } - - /** - * Creates a {@link Bucket} with an {@link Exemplar}. - * - * @param count the number of values in each bucket of the histogram. - * @param exemplar the {@code Exemplar} of this {@code Bucket}. - * @return a {@code Bucket}. - * @since 0.17 - */ - public static Bucket create(long count, Exemplar exemplar) { - Utils.checkArgument(count >= 0, "bucket count should be non-negative."); - Utils.checkNotNull(exemplar, "exemplar"); - return new AutoValue_Distribution_Bucket(count, exemplar); - } - - /** - * Returns the number of values in each bucket of the histogram. - * - * @return the number of values in each bucket of the histogram. - * @since 0.17 - */ - public abstract long getCount(); - - /** - * Returns the {@link Exemplar} associated with the {@link Bucket}, or {@code null} if there - * isn't one. - * - * @return the {@code Exemplar} associated with the {@code Bucket}, or {@code null} if there - * isn't one. - * @since 0.17 - */ - @Nullable - public abstract Exemplar getExemplar(); - } - - /** - * An example point that may be used to annotate aggregated distribution values, associated with a - * histogram bucket. - * - * @since 0.17 - */ - @Immutable - @AutoValue - public abstract static class Exemplar { - - Exemplar() {} - - /** - * Returns value of the {@link Exemplar} point. - * - * @return value of the {@code Exemplar} point. - * @since 0.17 - */ - public abstract double getValue(); - - /** - * Returns the time that this {@link Exemplar}'s value was recorded. - * - * @return the time that this {@code Exemplar}'s value was recorded. - * @since 0.17 - */ - public abstract Timestamp getTimestamp(); - - /** - * Returns the contextual information about the example value, represented as a string map. - * - * @return the contextual information about the example value. - * @since 0.17 - */ - public abstract Map getAttachments(); - - /** - * Creates an {@link Exemplar}. - * - * @param value value of the {@link Exemplar} point. - * @param timestamp the time that this {@code Exemplar}'s value was recorded. - * @param attachments the contextual information about the example value. - * @return an {@code Exemplar}. - * @since 0.17 - */ - public static Exemplar create( - double value, Timestamp timestamp, Map attachments) { - Utils.checkNotNull(attachments, "attachments"); - Map attachmentsCopy = - Collections.unmodifiableMap(new HashMap(attachments)); - for (Entry entry : attachmentsCopy.entrySet()) { - Utils.checkNotNull(entry.getKey(), "key of attachments"); - Utils.checkNotNull(entry.getValue(), "value of attachments"); - } - return new AutoValue_Distribution_Exemplar(value, timestamp, attachmentsCopy); - } - } -} diff --git a/api/src/main/java/io/opencensus/metrics/Metric.java b/api/src/main/java/io/opencensus/metrics/Metric.java deleted file mode 100644 index 0c108b56..00000000 --- a/api/src/main/java/io/opencensus/metrics/Metric.java +++ /dev/null @@ -1,104 +0,0 @@ -/* - * Copyright 2018, OpenCensus Authors - * - * 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 - * - * http://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.opencensus.metrics; - -import com.google.auto.value.AutoValue; -import io.opencensus.common.ExperimentalApi; -import io.opencensus.internal.Utils; -import io.opencensus.metrics.Value.ValueDistribution; -import io.opencensus.metrics.Value.ValueDouble; -import io.opencensus.metrics.Value.ValueLong; -import io.opencensus.metrics.Value.ValueSummary; -import java.util.List; -import javax.annotation.concurrent.Immutable; - -/** - * A {@link Metric} with one or more {@link TimeSeries}. - * - * @since 0.17 - */ -@ExperimentalApi -@Immutable -@AutoValue -public abstract class Metric { - - Metric() {} - - /** - * Creates a {@link Metric}. - * - * @param metricDescriptor the {@link MetricDescriptor}. - * @param timeSeriesList the {@link TimeSeries} list for this metric. - * @return a {@code Metric}. - * @since 0.17 - */ - public static Metric create(MetricDescriptor metricDescriptor, List timeSeriesList) { - checkTypeMatch(metricDescriptor.getType(), timeSeriesList); - return new AutoValue_Metric(metricDescriptor, timeSeriesList); - } - - /** - * Returns the {@link MetricDescriptor} of this metric. - * - * @return the {@code MetricDescriptor} of this metric. - * @since 0.17 - */ - public abstract MetricDescriptor getMetricDescriptor(); - - /** - * Returns the {@link TimeSeries} list for this metric. - * - *

The type of the {@link TimeSeries#getPoints()} must match {@link MetricDescriptor.Type}. - * - * @return the {@code TimeSeriesList} for this metric. - * @since 0.17 - */ - public abstract List getTimeSeriesList(); - - private static void checkTypeMatch(MetricDescriptor.Type type, List timeSeriesList) { - for (TimeSeries timeSeries : timeSeriesList) { - for (Point point : timeSeries.getPoints()) { - Value value = point.getValue(); - String valueClassName = ""; - if (value.getClass().getSuperclass() != null) { // work around nullness check - // AutoValue classes should always have a super class. - valueClassName = value.getClass().getSuperclass().getSimpleName(); - } - switch (type) { - case GAUGE_INT64: - case CUMULATIVE_INT64: - Utils.checkArgument( - value instanceof ValueLong, "Type mismatch: %s, %s.", type, valueClassName); - break; - case CUMULATIVE_DOUBLE: - case GAUGE_DOUBLE: - Utils.checkArgument( - value instanceof ValueDouble, "Type mismatch: %s, %s.", type, valueClassName); - break; - case GAUGE_DISTRIBUTION: - case CUMULATIVE_DISTRIBUTION: - Utils.checkArgument( - value instanceof ValueDistribution, "Type mismatch: %s, %s.", type, valueClassName); - break; - case SUMMARY: - Utils.checkArgument( - value instanceof ValueSummary, "Type mismatch: %s, %s.", type, valueClassName); - } - } - } - } -} diff --git a/api/src/main/java/io/opencensus/metrics/MetricDescriptor.java b/api/src/main/java/io/opencensus/metrics/MetricDescriptor.java deleted file mode 100644 index 5146cd85..00000000 --- a/api/src/main/java/io/opencensus/metrics/MetricDescriptor.java +++ /dev/null @@ -1,172 +0,0 @@ -/* - * Copyright 2018, OpenCensus Authors - * - * 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 - * - * http://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.opencensus.metrics; - -import com.google.auto.value.AutoValue; -import io.opencensus.common.ExperimentalApi; -import io.opencensus.internal.Utils; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import javax.annotation.concurrent.Immutable; - -/** - * {@link MetricDescriptor} defines a {@code Metric} type and its schema. - * - * @since 0.17 - */ -@ExperimentalApi -@Immutable -@AutoValue -public abstract class MetricDescriptor { - - MetricDescriptor() {} - - /** - * Creates a {@link MetricDescriptor}. - * - * @param name name of {@code MetricDescriptor}. - * @param description description of {@code MetricDescriptor}. - * @param unit the metric unit. - * @param type type of {@code MetricDescriptor}. - * @param labelKeys the label keys associated with the {@code MetricDescriptor}. - * @return a {@code MetricDescriptor}. - * @since 0.17 - */ - public static MetricDescriptor create( - String name, String description, String unit, Type type, List labelKeys) { - Utils.checkNotNull(labelKeys, "labelKeys"); - Utils.checkListElementNotNull(labelKeys, "labelKey"); - return new AutoValue_MetricDescriptor( - name, - description, - unit, - type, - Collections.unmodifiableList(new ArrayList(labelKeys))); - } - - /** - * Returns the metric descriptor name. - * - * @return the metric descriptor name. - * @since 0.17 - */ - public abstract String getName(); - - /** - * Returns the description of this metric descriptor. - * - * @return the description of this metric descriptor. - * @since 0.17 - */ - public abstract String getDescription(); - - /** - * Returns the unit of this metric descriptor. - * - * @return the unit of this metric descriptor. - * @since 0.17 - */ - public abstract String getUnit(); - - /** - * Returns the type of this metric descriptor. - * - * @return the type of this metric descriptor. - * @since 0.17 - */ - public abstract Type getType(); - - /** - * Returns the label keys associated with this metric descriptor. - * - * @return the label keys associated with this metric descriptor. - * @since 0.17 - */ - public abstract List getLabelKeys(); - - /** - * The kind of metric. It describes how the data is reported. - * - *

A gauge is an instantaneous measurement of a value. - * - *

A cumulative measurement is a value accumulated over a time interval. In a time series, - * cumulative measurements should have the same start time and increasing end times, until an - * event resets the cumulative value to zero and sets a new start time for the following points. - * - * @since 0.17 - */ - public enum Type { - - /** - * An instantaneous measurement of an int64 value. - * - * @since 0.17 - */ - GAUGE_INT64, - - /** - * An instantaneous measurement of a double value. - * - * @since 0.17 - */ - GAUGE_DOUBLE, - - /** - * An instantaneous measurement of a distribution value. The count and sum can go both up and - * down. Used in scenarios like a snapshot of time the current items in a queue have spent - * there. - * - * @since 0.17 - */ - GAUGE_DISTRIBUTION, - - /** - * An cumulative measurement of an int64 value. - * - * @since 0.17 - */ - CUMULATIVE_INT64, - - /** - * An cumulative measurement of a double value. - * - * @since 0.17 - */ - CUMULATIVE_DOUBLE, - - /** - * An cumulative measurement of a distribution value. The count and sum can only go up, if - * resets then the start_time should also be reset. - * - * @since 0.17 - */ - CUMULATIVE_DISTRIBUTION, - - /** - * Some frameworks implemented DISTRIBUTION as a summary of observations (usually things like - * request durations and response sizes). While it also provides a total count of observations - * and a sum of all observed values, it calculates configurable quantiles over a sliding time - * window. - * - *

This is not recommended, since it cannot be aggregated. - * - * @since 0.17 - */ - SUMMARY, - } -} diff --git a/api/src/main/java/io/opencensus/metrics/MetricProducer.java b/api/src/main/java/io/opencensus/metrics/MetricProducer.java deleted file mode 100644 index 86f9732f..00000000 --- a/api/src/main/java/io/opencensus/metrics/MetricProducer.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright 2018, OpenCensus Authors - * - * 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 - * - * http://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.opencensus.metrics; - -import io.opencensus.common.ExperimentalApi; -import io.opencensus.metrics.export.MetricProducerManager; -import java.util.Collection; - -/** - * A {@link Metric} producer that can be registered for exporting using {@link - * MetricProducerManager}. - * - *

All implementation MUST be thread-safe. - * - * @since 0.17 - */ -@ExperimentalApi -public abstract class MetricProducer { - - /** - * Returns a collection of produced {@link Metric}s to be exported. - * - * @return a collection of produced {@link Metric}s to be exported. - * @since 0.17 - */ - public abstract Collection getMetrics(); -} diff --git a/api/src/main/java/io/opencensus/metrics/MetricRegistry.java b/api/src/main/java/io/opencensus/metrics/MetricRegistry.java index c249d47b..a9987b75 100644 --- a/api/src/main/java/io/opencensus/metrics/MetricRegistry.java +++ b/api/src/main/java/io/opencensus/metrics/MetricRegistry.java @@ -24,7 +24,7 @@ import java.util.LinkedHashMap; /** * Creates and manages your application's set of metrics. The default implementation of this creates - * a {@link MetricProducer} and registers it to the global {@link + * a {@link io.opencensus.metrics.export.MetricProducer} and registers it to the global {@link * io.opencensus.metrics.export.MetricProducerManager}. * * @since 0.17 diff --git a/api/src/main/java/io/opencensus/metrics/Point.java b/api/src/main/java/io/opencensus/metrics/Point.java deleted file mode 100644 index 9ef7c15b..00000000 --- a/api/src/main/java/io/opencensus/metrics/Point.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright 2018, OpenCensus Authors - * - * 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 - * - * http://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.opencensus.metrics; - -import com.google.auto.value.AutoValue; -import io.opencensus.common.ExperimentalApi; -import io.opencensus.common.Timestamp; -import javax.annotation.concurrent.Immutable; - -/** - * A timestamped measurement of a {@code TimeSeries}. - * - * @since 0.17 - */ -@ExperimentalApi -@AutoValue -@Immutable -public abstract class Point { - - Point() {} - - /** - * Creates a {@link Point}. - * - * @param value the {@link Value} of this {@link Point}. - * @param timestamp the {@link Timestamp} when this {@link Point} was recorded. - * @return a {@code Point}. - * @since 0.17 - */ - public static Point create(Value value, Timestamp timestamp) { - return new AutoValue_Point(value, timestamp); - } - - /** - * Returns the {@link Value}. - * - * @return the {@code Value}. - * @since 0.17 - */ - public abstract Value getValue(); - - /** - * Returns the {@link Timestamp} when this {@link Point} was recorded. - * - * @return the {@code Timestamp}. - * @since 0.17 - */ - public abstract Timestamp getTimestamp(); -} diff --git a/api/src/main/java/io/opencensus/metrics/Summary.java b/api/src/main/java/io/opencensus/metrics/Summary.java deleted file mode 100644 index f23667bb..00000000 --- a/api/src/main/java/io/opencensus/metrics/Summary.java +++ /dev/null @@ -1,187 +0,0 @@ -/* - * Copyright 2018, OpenCensus Authors - * - * 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 - * - * http://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.opencensus.metrics; - -import com.google.auto.value.AutoValue; -import io.opencensus.common.ExperimentalApi; -import io.opencensus.internal.Utils; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import javax.annotation.Nullable; -import javax.annotation.concurrent.Immutable; - -/** - * Implementation of the {@link Distribution} as a summary of observations. - * - *

This is not recommended, since it cannot be aggregated. - * - * @since 0.17 - */ -@ExperimentalApi -@AutoValue -@Immutable -public abstract class Summary { - Summary() {} - - /** - * Creates a {@link Summary}. - * - * @param count the count of the population values. - * @param sum the sum of the population values. - * @param snapshot bucket boundaries of a histogram. - * @return a {@code Summary} with the given values. - * @since 0.17 - */ - public static Summary create(@Nullable Long count, @Nullable Double sum, Snapshot snapshot) { - checkCountAndSum(count, sum); - Utils.checkNotNull(snapshot, "snapshot"); - return new AutoValue_Summary(count, sum, snapshot); - } - - /** - * Returns the aggregated count. If not available returns {@code null}. - * - * @return the aggregated count. - * @since 0.17 - */ - @Nullable - public abstract Long getCount(); - - /** - * Returns the aggregated sum. If not available returns {@code null}. - * - * @return the aggregated sum. - * @since 0.17 - */ - @Nullable - public abstract Double getSum(); - - /** - * Returns the {@link Snapshot}. - * - * @return the {@code Snapshot}. - * @since 0.17 - */ - public abstract Snapshot getSnapshot(); - - /** - * Represents the summary observation of the recorded events over a sliding time window. - * - * @since 0.17 - */ - @Immutable - @AutoValue - public abstract static class Snapshot { - /** - * Returns the number of values in this {@code Snapshot}. If not available returns {@code null}. - * - * @return the number of values in this {@code Snapshot}. - * @since 0.17 - */ - @Nullable - public abstract Long getCount(); - - /** - * Returns the sum of values in this {@code Snapshot}. If not available returns {@code null}. - * - * @return the sum of values in this {@code Snapshot}. - * @since 0.17 - */ - @Nullable - public abstract Double getSum(); - - /** - * Returns the list of {@code ValueAtPercentile}s in this {@code Snapshot}. - * - * @return the list of {@code ValueAtPercentile}s in this {@code Snapshot}. - * @since 0.17 - */ - public abstract List getValueAtPercentiles(); - - /** - * Creates a {@link Snapshot}. - * - * @param count the number of values in this {@code Snapshot}. - * @param sum the number of values in this {@code Snapshot}. - * @param valueAtPercentiles the list of {@code ValueAtPercentile}. - * @return a {@code Snapshot} with the given values. - * @since 0.17 - */ - public static Snapshot create( - @Nullable Long count, @Nullable Double sum, List valueAtPercentiles) { - checkCountAndSum(count, sum); - Utils.checkNotNull(valueAtPercentiles, "valueAtPercentiles"); - Utils.checkListElementNotNull(valueAtPercentiles, "value in valueAtPercentiles"); - return new AutoValue_Summary_Snapshot( - count, - sum, - Collections.unmodifiableList(new ArrayList(valueAtPercentiles))); - } - - /** - * Represents the value at a given percentile of a distribution. - * - * @since 0.17 - */ - @Immutable - @AutoValue - public abstract static class ValueAtPercentile { - /** - * Returns the percentile in this {@code ValueAtPercentile}. - * - *

Must be in the interval (0.0, 100.0]. - * - * @return the percentile in this {@code ValueAtPercentile}. - * @since 0.17 - */ - public abstract double getPercentile(); - - /** - * Returns the value in this {@code ValueAtPercentile}. - * - * @return the value in this {@code ValueAtPercentile}. - * @since 0.17 - */ - public abstract double getValue(); - - /** - * Creates a {@link ValueAtPercentile}. - * - * @param percentile the percentile in this {@code ValueAtPercentile}. - * @param value the value in this {@code ValueAtPercentile}. - * @return a {@code ValueAtPercentile} with the given values. - * @since 0.17 - */ - public static ValueAtPercentile create(double percentile, double value) { - Utils.checkArgument( - 0 < percentile && percentile <= 100.0, - "percentile must be in the interval (0.0, 100.0]"); - Utils.checkArgument(value >= 0, "value must be non-negative"); - return new AutoValue_Summary_Snapshot_ValueAtPercentile(percentile, value); - } - } - } - - private static void checkCountAndSum(@Nullable Long count, @Nullable Double sum) { - Utils.checkArgument(count == null || count >= 0, "count must be non-negative."); - Utils.checkArgument(sum == null || sum >= 0, "sum must be non-negative."); - if (count != null && count == 0) { - Utils.checkArgument(sum == null || sum == 0, "sum must be 0 if count is 0."); - } - } -} diff --git a/api/src/main/java/io/opencensus/metrics/TimeSeries.java b/api/src/main/java/io/opencensus/metrics/TimeSeries.java deleted file mode 100644 index d504dad9..00000000 --- a/api/src/main/java/io/opencensus/metrics/TimeSeries.java +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Copyright 2018, OpenCensus Authors - * - * 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 - * - * http://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.opencensus.metrics; - -import com.google.auto.value.AutoValue; -import io.opencensus.common.ExperimentalApi; -import io.opencensus.common.Timestamp; -import io.opencensus.internal.Utils; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import javax.annotation.Nullable; -import javax.annotation.concurrent.Immutable; - -/** - * A collection of data points that describes the time-varying values of a {@code Metric}. - * - * @since 0.17 - */ -@ExperimentalApi -@Immutable -@AutoValue -public abstract class TimeSeries { - - TimeSeries() {} - - /** - * Creates a {@link TimeSeries}. - * - * @param labelValues the {@code LabelValue}s that uniquely identify this {@code TimeSeries}. - * @param points the data {@code Point}s of this {@code TimeSeries}. - * @param startTimestamp the start {@code Timestamp} of this {@code TimeSeries}. Must be non-null - * for cumulative {@code Point}s. - * @return a {@code TimeSeries}. - * @since 0.17 - */ - public static TimeSeries create( - List labelValues, List points, @Nullable Timestamp startTimestamp) { - // Fail fast on null lists to prevent NullPointerException when copying the lists. - Utils.checkNotNull(labelValues, "labelValues"); - Utils.checkNotNull(points, "points"); - Utils.checkListElementNotNull(labelValues, "labelValue"); - Utils.checkListElementNotNull(points, "point"); - return new AutoValue_TimeSeries( - Collections.unmodifiableList(new ArrayList(labelValues)), - Collections.unmodifiableList(new ArrayList(points)), - startTimestamp); - } - - /** - * Returns the set of {@link LabelValue}s that uniquely identify this {@link TimeSeries}. - * - *

Apply to all {@link Point}s. - * - *

The order of {@link LabelValue}s must match that of {@link LabelKey}s in the {@code - * MetricDescriptor}. - * - * @return the {@code LabelValue}s. - * @since 0.17 - */ - public abstract List getLabelValues(); - - /** - * Returns the data {@link Point}s of this {@link TimeSeries}. - * - * @return the data {@code Point}s. - * @since 0.17 - */ - public abstract List getPoints(); - - /** - * Returns the start {@link Timestamp} of this {@link TimeSeries} if the {@link Point}s are - * cumulative, or {@code null} if the {@link Point}s are gauge. - * - * @return the start {@code Timestamp} or {@code null}. - * @since 0.17 - */ - @Nullable - public abstract Timestamp getStartTimestamp(); -} diff --git a/api/src/main/java/io/opencensus/metrics/Value.java b/api/src/main/java/io/opencensus/metrics/Value.java deleted file mode 100644 index 1bc63b79..00000000 --- a/api/src/main/java/io/opencensus/metrics/Value.java +++ /dev/null @@ -1,246 +0,0 @@ -/* - * Copyright 2018, OpenCensus Authors - * - * 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 - * - * http://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.opencensus.metrics; - -import com.google.auto.value.AutoValue; -import io.opencensus.common.ExperimentalApi; -import io.opencensus.common.Function; -import javax.annotation.concurrent.Immutable; - -/** - * The actual point value for a {@link Point}. - * - *

Currently there are three types of {@link Value}: - * - *

    - *
  • {@code double} - *
  • {@code long} - *
  • {@link Distribution} - *
- * - *

Each {@link Point} contains exactly one of the three {@link Value} types. - * - * @since 0.17 - */ -@ExperimentalApi -@Immutable -public abstract class Value { - - Value() {} - - /** - * Returns a double {@link Value}. - * - * @param value value in double. - * @return a double {@code Value}. - * @since 0.17 - */ - public static Value doubleValue(double value) { - return ValueDouble.create(value); - } - - /** - * Returns a long {@link Value}. - * - * @param value value in long. - * @return a long {@code Value}. - * @since 0.17 - */ - public static Value longValue(long value) { - return ValueLong.create(value); - } - - /** - * Returns a {@link Distribution} {@link Value}. - * - * @param value value in {@link Distribution}. - * @return a {@code Distribution} {@code Value}. - * @since 0.17 - */ - public static Value distributionValue(Distribution value) { - return ValueDistribution.create(value); - } - - /** - * Returns a {@link Summary} {@link Value}. - * - * @param value value in {@link Summary}. - * @return a {@code Summary} {@code Value}. - * @since 0.17 - */ - public static Value summaryValue(Summary value) { - return ValueSummary.create(value); - } - - /** - * Applies the given match function to the underlying data type. - * - * @since 0.17 - */ - public abstract T match( - Function doubleFunction, - Function longFunction, - Function distributionFunction, - Function summaryFunction, - Function defaultFunction); - - /** A 64-bit double-precision floating-point {@link Value}. */ - @AutoValue - @Immutable - abstract static class ValueDouble extends Value { - - ValueDouble() {} - - @Override - public final T match( - Function doubleFunction, - Function longFunction, - Function distributionFunction, - Function summaryFunction, - Function defaultFunction) { - return doubleFunction.apply(getValue()); - } - - /** - * Creates a {@link ValueDouble}. - * - * @param value the value in double. - * @return a {@code ValueDouble}. - */ - static ValueDouble create(double value) { - return new AutoValue_Value_ValueDouble(value); - } - - /** - * Returns the double value. - * - * @return the double value. - */ - abstract double getValue(); - } - - /** A 64-bit integer {@link Value}. */ - @AutoValue - @Immutable - abstract static class ValueLong extends Value { - - ValueLong() {} - - @Override - public final T match( - Function doubleFunction, - Function longFunction, - Function distributionFunction, - Function summaryFunction, - Function defaultFunction) { - return longFunction.apply(getValue()); - } - - /** - * Creates a {@link ValueLong}. - * - * @param value the value in long. - * @return a {@code ValueLong}. - */ - static ValueLong create(long value) { - return new AutoValue_Value_ValueLong(value); - } - - /** - * Returns the long value. - * - * @return the long value. - */ - abstract long getValue(); - } - - /** - * {@link ValueDistribution} contains summary statistics for a population of values. It optionally - * contains a histogram representing the distribution of those values across a set of buckets. - */ - @AutoValue - @Immutable - abstract static class ValueDistribution extends Value { - - ValueDistribution() {} - - @Override - public final T match( - Function doubleFunction, - Function longFunction, - Function distributionFunction, - Function summaryFunction, - Function defaultFunction) { - return distributionFunction.apply(getValue()); - } - - /** - * Creates a {@link ValueDistribution}. - * - * @param value the {@link Distribution} value. - * @return a {@code ValueDistribution}. - */ - static ValueDistribution create(Distribution value) { - return new AutoValue_Value_ValueDistribution(value); - } - - /** - * Returns the {@link Distribution} value. - * - * @return the {@code Distribution} value. - */ - abstract Distribution getValue(); - } - - /** - * {@link ValueSummary} contains a snapshot representing values calculated over an arbitrary time - * window. - */ - @AutoValue - @Immutable - abstract static class ValueSummary extends Value { - - ValueSummary() {} - - @Override - public final T match( - Function doubleFunction, - Function longFunction, - Function distributionFunction, - Function summaryFunction, - Function defaultFunction) { - return summaryFunction.apply(getValue()); - } - - /** - * Creates a {@link ValueSummary}. - * - * @param value the {@link Summary} value. - * @return a {@code ValueSummary}. - */ - static ValueSummary create(Summary value) { - return new AutoValue_Value_ValueSummary(value); - } - - /** - * Returns the {@link Summary} value. - * - * @return the {@code Summary} value. - */ - abstract Summary getValue(); - } -} diff --git a/api/src/main/java/io/opencensus/metrics/export/Distribution.java b/api/src/main/java/io/opencensus/metrics/export/Distribution.java new file mode 100644 index 00000000..dc9fa9e9 --- /dev/null +++ b/api/src/main/java/io/opencensus/metrics/export/Distribution.java @@ -0,0 +1,280 @@ +/* + * Copyright 2018, OpenCensus Authors + * + * 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 + * + * http://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.opencensus.metrics.export; + +import com.google.auto.value.AutoValue; +import io.opencensus.common.ExperimentalApi; +import io.opencensus.common.Timestamp; +import io.opencensus.internal.Utils; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import javax.annotation.Nullable; +import javax.annotation.concurrent.Immutable; + +/** + * {@link Distribution} contains summary statistics for a population of values. It optionally + * contains a histogram representing the distribution of those values across a set of buckets. + * + * @since 0.17 + */ +@ExperimentalApi +@AutoValue +@Immutable +public abstract class Distribution { + + Distribution() {} + + /** + * Creates a {@link Distribution}. + * + * @param count the count of the population values. + * @param sum the sum of the population values. + * @param sumOfSquaredDeviations the sum of squared deviations of the population values. + * @param bucketBoundaries bucket boundaries of a histogram. + * @param buckets {@link Bucket}s of a histogram. + * @return a {@code Distribution}. + * @since 0.17 + */ + public static Distribution create( + long count, + double sum, + double sumOfSquaredDeviations, + List bucketBoundaries, + List buckets) { + Utils.checkArgument(count >= 0, "count should be non-negative."); + Utils.checkArgument( + sumOfSquaredDeviations >= 0, "sum of squared deviations should be non-negative."); + if (count == 0) { + Utils.checkArgument(sum == 0, "sum should be 0 if count is 0."); + Utils.checkArgument( + sumOfSquaredDeviations == 0, "sum of squared deviations should be 0 if count is 0."); + } + return new AutoValue_Distribution( + count, + sum, + sumOfSquaredDeviations, + copyBucketBounds(bucketBoundaries), + copyBucketCount(buckets)); + } + + private static List copyBucketBounds(List bucketBoundaries) { + Utils.checkNotNull(bucketBoundaries, "bucketBoundaries list should not be null."); + List bucketBoundariesCopy = new ArrayList(bucketBoundaries); // Deep copy. + // Check if sorted. + if (bucketBoundariesCopy.size() > 1) { + double lower = bucketBoundariesCopy.get(0); + for (int i = 1; i < bucketBoundariesCopy.size(); i++) { + double next = bucketBoundariesCopy.get(i); + Utils.checkArgument(lower < next, "bucket boundaries not sorted."); + lower = next; + } + } + return Collections.unmodifiableList(bucketBoundariesCopy); + } + + private static List copyBucketCount(List buckets) { + Utils.checkNotNull(buckets, "bucket list should not be null."); + List bucketsCopy = new ArrayList(buckets); + for (Bucket bucket : bucketsCopy) { + Utils.checkNotNull(bucket, "bucket should not be null."); + } + return Collections.unmodifiableList(bucketsCopy); + } + + /** + * Returns the aggregated count. + * + * @return the aggregated count. + * @since 0.17 + */ + public abstract long getCount(); + + /** + * Returns the aggregated sum. + * + * @return the aggregated sum. + * @since 0.17 + */ + public abstract double getSum(); + + /** + * Returns the aggregated sum of squared deviations. + * + *

The sum of squared deviations from the mean of the values in the population. For values x_i + * this is: + * + *

Sum[i=1..n]((x_i - mean)^2) + * + *

If count is zero then this field must be zero. + * + * @return the aggregated sum of squared deviations. + * @since 0.17 + */ + public abstract double getSumOfSquaredDeviations(); + + /** + * Returns the bucket boundaries of this distribution. + * + *

The bucket boundaries for that histogram are described by bucket_bounds. This defines + * size(bucket_bounds) + 1 (= N) buckets. The boundaries for bucket index i are: + * + *

    + *
  • {@code (-infinity, bucket_bounds[i]) for i == 0} + *
  • {@code [bucket_bounds[i-1], bucket_bounds[i]) for 0 < i < N-2} + *
  • {@code [bucket_bounds[i-1], +infinity) for i == N-1} + *
+ * + *

i.e. an underflow bucket (number 0), zero or more finite buckets (1 through N - 2, and an + * overflow bucket (N - 1), with inclusive lower bounds and exclusive upper bounds. + * + *

If bucket_bounds has no elements (zero size), then there is no histogram associated with the + * Distribution. If bucket_bounds has only one element, there are no finite buckets, and that + * single element is the common boundary of the overflow and underflow buckets. The values must be + * monotonically increasing. + * + * @return the bucket boundaries of this distribution. + * @since 0.17 + */ + public abstract List getBucketBoundaries(); + + /** + * Returns the aggregated histogram {@link Bucket}s. + * + * @return the aggregated histogram buckets. + * @since 0.17 + */ + public abstract List getBuckets(); + + /** + * The histogram bucket of the population values. + * + * @since 0.17 + */ + @AutoValue + @Immutable + public abstract static class Bucket { + + Bucket() {} + + /** + * Creates a {@link Bucket}. + * + * @param count the number of values in each bucket of the histogram. + * @return a {@code Bucket}. + * @since 0.17 + */ + public static Bucket create(long count) { + Utils.checkArgument(count >= 0, "bucket count should be non-negative."); + return new AutoValue_Distribution_Bucket(count, null); + } + + /** + * Creates a {@link Bucket} with an {@link Exemplar}. + * + * @param count the number of values in each bucket of the histogram. + * @param exemplar the {@code Exemplar} of this {@code Bucket}. + * @return a {@code Bucket}. + * @since 0.17 + */ + public static Bucket create(long count, Exemplar exemplar) { + Utils.checkArgument(count >= 0, "bucket count should be non-negative."); + Utils.checkNotNull(exemplar, "exemplar"); + return new AutoValue_Distribution_Bucket(count, exemplar); + } + + /** + * Returns the number of values in each bucket of the histogram. + * + * @return the number of values in each bucket of the histogram. + * @since 0.17 + */ + public abstract long getCount(); + + /** + * Returns the {@link Exemplar} associated with the {@link Bucket}, or {@code null} if there + * isn't one. + * + * @return the {@code Exemplar} associated with the {@code Bucket}, or {@code null} if there + * isn't one. + * @since 0.17 + */ + @Nullable + public abstract Exemplar getExemplar(); + } + + /** + * An example point that may be used to annotate aggregated distribution values, associated with a + * histogram bucket. + * + * @since 0.17 + */ + @Immutable + @AutoValue + public abstract static class Exemplar { + + Exemplar() {} + + /** + * Returns value of the {@link Exemplar} point. + * + * @return value of the {@code Exemplar} point. + * @since 0.17 + */ + public abstract double getValue(); + + /** + * Returns the time that this {@link Exemplar}'s value was recorded. + * + * @return the time that this {@code Exemplar}'s value was recorded. + * @since 0.17 + */ + public abstract Timestamp getTimestamp(); + + /** + * Returns the contextual information about the example value, represented as a string map. + * + * @return the contextual information about the example value. + * @since 0.17 + */ + public abstract Map getAttachments(); + + /** + * Creates an {@link Exemplar}. + * + * @param value value of the {@link Exemplar} point. + * @param timestamp the time that this {@code Exemplar}'s value was recorded. + * @param attachments the contextual information about the example value. + * @return an {@code Exemplar}. + * @since 0.17 + */ + public static Exemplar create( + double value, Timestamp timestamp, Map attachments) { + Utils.checkNotNull(attachments, "attachments"); + Map attachmentsCopy = + Collections.unmodifiableMap(new HashMap(attachments)); + for (Entry entry : attachmentsCopy.entrySet()) { + Utils.checkNotNull(entry.getKey(), "key of attachments"); + Utils.checkNotNull(entry.getValue(), "value of attachments"); + } + return new AutoValue_Distribution_Exemplar(value, timestamp, attachmentsCopy); + } + } +} diff --git a/api/src/main/java/io/opencensus/metrics/export/Metric.java b/api/src/main/java/io/opencensus/metrics/export/Metric.java new file mode 100644 index 00000000..07fe356a --- /dev/null +++ b/api/src/main/java/io/opencensus/metrics/export/Metric.java @@ -0,0 +1,104 @@ +/* + * Copyright 2018, OpenCensus Authors + * + * 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 + * + * http://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.opencensus.metrics.export; + +import com.google.auto.value.AutoValue; +import io.opencensus.common.ExperimentalApi; +import io.opencensus.internal.Utils; +import io.opencensus.metrics.export.Value.ValueDistribution; +import io.opencensus.metrics.export.Value.ValueDouble; +import io.opencensus.metrics.export.Value.ValueLong; +import io.opencensus.metrics.export.Value.ValueSummary; +import java.util.List; +import javax.annotation.concurrent.Immutable; + +/** + * A {@link Metric} with one or more {@link TimeSeries}. + * + * @since 0.17 + */ +@ExperimentalApi +@Immutable +@AutoValue +public abstract class Metric { + + Metric() {} + + /** + * Creates a {@link Metric}. + * + * @param metricDescriptor the {@link MetricDescriptor}. + * @param timeSeriesList the {@link TimeSeries} list for this metric. + * @return a {@code Metric}. + * @since 0.17 + */ + public static Metric create(MetricDescriptor metricDescriptor, List timeSeriesList) { + checkTypeMatch(metricDescriptor.getType(), timeSeriesList); + return new AutoValue_Metric(metricDescriptor, timeSeriesList); + } + + /** + * Returns the {@link MetricDescriptor} of this metric. + * + * @return the {@code MetricDescriptor} of this metric. + * @since 0.17 + */ + public abstract MetricDescriptor getMetricDescriptor(); + + /** + * Returns the {@link TimeSeries} list for this metric. + * + *

The type of the {@link TimeSeries#getPoints()} must match {@link MetricDescriptor.Type}. + * + * @return the {@code TimeSeriesList} for this metric. + * @since 0.17 + */ + public abstract List getTimeSeriesList(); + + private static void checkTypeMatch(MetricDescriptor.Type type, List timeSeriesList) { + for (TimeSeries timeSeries : timeSeriesList) { + for (Point point : timeSeries.getPoints()) { + Value value = point.getValue(); + String valueClassName = ""; + if (value.getClass().getSuperclass() != null) { // work around nullness check + // AutoValue classes should always have a super class. + valueClassName = value.getClass().getSuperclass().getSimpleName(); + } + switch (type) { + case GAUGE_INT64: + case CUMULATIVE_INT64: + Utils.checkArgument( + value instanceof ValueLong, "Type mismatch: %s, %s.", type, valueClassName); + break; + case CUMULATIVE_DOUBLE: + case GAUGE_DOUBLE: + Utils.checkArgument( + value instanceof ValueDouble, "Type mismatch: %s, %s.", type, valueClassName); + break; + case GAUGE_DISTRIBUTION: + case CUMULATIVE_DISTRIBUTION: + Utils.checkArgument( + value instanceof ValueDistribution, "Type mismatch: %s, %s.", type, valueClassName); + break; + case SUMMARY: + Utils.checkArgument( + value instanceof ValueSummary, "Type mismatch: %s, %s.", type, valueClassName); + } + } + } + } +} diff --git a/api/src/main/java/io/opencensus/metrics/export/MetricDescriptor.java b/api/src/main/java/io/opencensus/metrics/export/MetricDescriptor.java new file mode 100644 index 00000000..a4629f8e --- /dev/null +++ b/api/src/main/java/io/opencensus/metrics/export/MetricDescriptor.java @@ -0,0 +1,173 @@ +/* + * Copyright 2018, OpenCensus Authors + * + * 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 + * + * http://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.opencensus.metrics.export; + +import com.google.auto.value.AutoValue; +import io.opencensus.common.ExperimentalApi; +import io.opencensus.internal.Utils; +import io.opencensus.metrics.LabelKey; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import javax.annotation.concurrent.Immutable; + +/** + * {@link MetricDescriptor} defines a {@code Metric} type and its schema. + * + * @since 0.17 + */ +@ExperimentalApi +@Immutable +@AutoValue +public abstract class MetricDescriptor { + + MetricDescriptor() {} + + /** + * Creates a {@link MetricDescriptor}. + * + * @param name name of {@code MetricDescriptor}. + * @param description description of {@code MetricDescriptor}. + * @param unit the metric unit. + * @param type type of {@code MetricDescriptor}. + * @param labelKeys the label keys associated with the {@code MetricDescriptor}. + * @return a {@code MetricDescriptor}. + * @since 0.17 + */ + public static MetricDescriptor create( + String name, String description, String unit, Type type, List labelKeys) { + Utils.checkNotNull(labelKeys, "labelKeys"); + Utils.checkListElementNotNull(labelKeys, "labelKey"); + return new AutoValue_MetricDescriptor( + name, + description, + unit, + type, + Collections.unmodifiableList(new ArrayList(labelKeys))); + } + + /** + * Returns the metric descriptor name. + * + * @return the metric descriptor name. + * @since 0.17 + */ + public abstract String getName(); + + /** + * Returns the description of this metric descriptor. + * + * @return the description of this metric descriptor. + * @since 0.17 + */ + public abstract String getDescription(); + + /** + * Returns the unit of this metric descriptor. + * + * @return the unit of this metric descriptor. + * @since 0.17 + */ + public abstract String getUnit(); + + /** + * Returns the type of this metric descriptor. + * + * @return the type of this metric descriptor. + * @since 0.17 + */ + public abstract Type getType(); + + /** + * Returns the label keys associated with this metric descriptor. + * + * @return the label keys associated with this metric descriptor. + * @since 0.17 + */ + public abstract List getLabelKeys(); + + /** + * The kind of metric. It describes how the data is reported. + * + *

A gauge is an instantaneous measurement of a value. + * + *

A cumulative measurement is a value accumulated over a time interval. In a time series, + * cumulative measurements should have the same start time and increasing end times, until an + * event resets the cumulative value to zero and sets a new start time for the following points. + * + * @since 0.17 + */ + public enum Type { + + /** + * An instantaneous measurement of an int64 value. + * + * @since 0.17 + */ + GAUGE_INT64, + + /** + * An instantaneous measurement of a double value. + * + * @since 0.17 + */ + GAUGE_DOUBLE, + + /** + * An instantaneous measurement of a distribution value. The count and sum can go both up and + * down. Used in scenarios like a snapshot of time the current items in a queue have spent + * there. + * + * @since 0.17 + */ + GAUGE_DISTRIBUTION, + + /** + * An cumulative measurement of an int64 value. + * + * @since 0.17 + */ + CUMULATIVE_INT64, + + /** + * An cumulative measurement of a double value. + * + * @since 0.17 + */ + CUMULATIVE_DOUBLE, + + /** + * An cumulative measurement of a distribution value. The count and sum can only go up, if + * resets then the start_time should also be reset. + * + * @since 0.17 + */ + CUMULATIVE_DISTRIBUTION, + + /** + * Some frameworks implemented DISTRIBUTION as a summary of observations (usually things like + * request durations and response sizes). While it also provides a total count of observations + * and a sum of all observed values, it calculates configurable quantiles over a sliding time + * window. + * + *

This is not recommended, since it cannot be aggregated. + * + * @since 0.17 + */ + SUMMARY, + } +} diff --git a/api/src/main/java/io/opencensus/metrics/export/MetricProducer.java b/api/src/main/java/io/opencensus/metrics/export/MetricProducer.java new file mode 100644 index 00000000..739a0a9f --- /dev/null +++ b/api/src/main/java/io/opencensus/metrics/export/MetricProducer.java @@ -0,0 +1,40 @@ +/* + * Copyright 2018, OpenCensus Authors + * + * 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 + * + * http://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.opencensus.metrics.export; + +import io.opencensus.common.ExperimentalApi; +import java.util.Collection; + +/** + * A {@link Metric} producer that can be registered for exporting using {@link + * MetricProducerManager}. + * + *

All implementation MUST be thread-safe. + * + * @since 0.17 + */ +@ExperimentalApi +public abstract class MetricProducer { + + /** + * Returns a collection of produced {@link Metric}s to be exported. + * + * @return a collection of produced {@link Metric}s to be exported. + * @since 0.17 + */ + public abstract Collection getMetrics(); +} diff --git a/api/src/main/java/io/opencensus/metrics/export/MetricProducerManager.java b/api/src/main/java/io/opencensus/metrics/export/MetricProducerManager.java index fc864200..304d9294 100644 --- a/api/src/main/java/io/opencensus/metrics/export/MetricProducerManager.java +++ b/api/src/main/java/io/opencensus/metrics/export/MetricProducerManager.java @@ -18,7 +18,6 @@ package io.opencensus.metrics.export; import io.opencensus.common.ExperimentalApi; import io.opencensus.internal.Utils; -import io.opencensus.metrics.MetricProducer; import java.util.Collections; import java.util.Set; import javax.annotation.concurrent.ThreadSafe; diff --git a/api/src/main/java/io/opencensus/metrics/export/Point.java b/api/src/main/java/io/opencensus/metrics/export/Point.java new file mode 100644 index 00000000..1f382f9b --- /dev/null +++ b/api/src/main/java/io/opencensus/metrics/export/Point.java @@ -0,0 +1,63 @@ +/* + * Copyright 2018, OpenCensus Authors + * + * 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 + * + * http://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.opencensus.metrics.export; + +import com.google.auto.value.AutoValue; +import io.opencensus.common.ExperimentalApi; +import io.opencensus.common.Timestamp; +import javax.annotation.concurrent.Immutable; + +/** + * A timestamped measurement of a {@code TimeSeries}. + * + * @since 0.17 + */ +@ExperimentalApi +@AutoValue +@Immutable +public abstract class Point { + + Point() {} + + /** + * Creates a {@link Point}. + * + * @param value the {@link Value} of this {@link Point}. + * @param timestamp the {@link Timestamp} when this {@link Point} was recorded. + * @return a {@code Point}. + * @since 0.17 + */ + public static Point create(Value value, Timestamp timestamp) { + return new AutoValue_Point(value, timestamp); + } + + /** + * Returns the {@link Value}. + * + * @return the {@code Value}. + * @since 0.17 + */ + public abstract Value getValue(); + + /** + * Returns the {@link Timestamp} when this {@link Point} was recorded. + * + * @return the {@code Timestamp}. + * @since 0.17 + */ + public abstract Timestamp getTimestamp(); +} diff --git a/api/src/main/java/io/opencensus/metrics/export/Summary.java b/api/src/main/java/io/opencensus/metrics/export/Summary.java new file mode 100644 index 00000000..c82ca961 --- /dev/null +++ b/api/src/main/java/io/opencensus/metrics/export/Summary.java @@ -0,0 +1,187 @@ +/* + * Copyright 2018, OpenCensus Authors + * + * 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 + * + * http://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.opencensus.metrics.export; + +import com.google.auto.value.AutoValue; +import io.opencensus.common.ExperimentalApi; +import io.opencensus.internal.Utils; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import javax.annotation.Nullable; +import javax.annotation.concurrent.Immutable; + +/** + * Implementation of the {@link Distribution} as a summary of observations. + * + *

This is not recommended, since it cannot be aggregated. + * + * @since 0.17 + */ +@ExperimentalApi +@AutoValue +@Immutable +public abstract class Summary { + Summary() {} + + /** + * Creates a {@link Summary}. + * + * @param count the count of the population values. + * @param sum the sum of the population values. + * @param snapshot bucket boundaries of a histogram. + * @return a {@code Summary} with the given values. + * @since 0.17 + */ + public static Summary create(@Nullable Long count, @Nullable Double sum, Snapshot snapshot) { + checkCountAndSum(count, sum); + Utils.checkNotNull(snapshot, "snapshot"); + return new AutoValue_Summary(count, sum, snapshot); + } + + /** + * Returns the aggregated count. If not available returns {@code null}. + * + * @return the aggregated count. + * @since 0.17 + */ + @Nullable + public abstract Long getCount(); + + /** + * Returns the aggregated sum. If not available returns {@code null}. + * + * @return the aggregated sum. + * @since 0.17 + */ + @Nullable + public abstract Double getSum(); + + /** + * Returns the {@link Snapshot}. + * + * @return the {@code Snapshot}. + * @since 0.17 + */ + public abstract Snapshot getSnapshot(); + + /** + * Represents the summary observation of the recorded events over a sliding time window. + * + * @since 0.17 + */ + @Immutable + @AutoValue + public abstract static class Snapshot { + /** + * Returns the number of values in this {@code Snapshot}. If not available returns {@code null}. + * + * @return the number of values in this {@code Snapshot}. + * @since 0.17 + */ + @Nullable + public abstract Long getCount(); + + /** + * Returns the sum of values in this {@code Snapshot}. If not available returns {@code null}. + * + * @return the sum of values in this {@code Snapshot}. + * @since 0.17 + */ + @Nullable + public abstract Double getSum(); + + /** + * Returns the list of {@code ValueAtPercentile}s in this {@code Snapshot}. + * + * @return the list of {@code ValueAtPercentile}s in this {@code Snapshot}. + * @since 0.17 + */ + public abstract List getValueAtPercentiles(); + + /** + * Creates a {@link Snapshot}. + * + * @param count the number of values in this {@code Snapshot}. + * @param sum the number of values in this {@code Snapshot}. + * @param valueAtPercentiles the list of {@code ValueAtPercentile}. + * @return a {@code Snapshot} with the given values. + * @since 0.17 + */ + public static Snapshot create( + @Nullable Long count, @Nullable Double sum, List valueAtPercentiles) { + checkCountAndSum(count, sum); + Utils.checkNotNull(valueAtPercentiles, "valueAtPercentiles"); + Utils.checkListElementNotNull(valueAtPercentiles, "value in valueAtPercentiles"); + return new AutoValue_Summary_Snapshot( + count, + sum, + Collections.unmodifiableList(new ArrayList(valueAtPercentiles))); + } + + /** + * Represents the value at a given percentile of a distribution. + * + * @since 0.17 + */ + @Immutable + @AutoValue + public abstract static class ValueAtPercentile { + /** + * Returns the percentile in this {@code ValueAtPercentile}. + * + *

Must be in the interval (0.0, 100.0]. + * + * @return the percentile in this {@code ValueAtPercentile}. + * @since 0.17 + */ + public abstract double getPercentile(); + + /** + * Returns the value in this {@code ValueAtPercentile}. + * + * @return the value in this {@code ValueAtPercentile}. + * @since 0.17 + */ + public abstract double getValue(); + + /** + * Creates a {@link ValueAtPercentile}. + * + * @param percentile the percentile in this {@code ValueAtPercentile}. + * @param value the value in this {@code ValueAtPercentile}. + * @return a {@code ValueAtPercentile} with the given values. + * @since 0.17 + */ + public static ValueAtPercentile create(double percentile, double value) { + Utils.checkArgument( + 0 < percentile && percentile <= 100.0, + "percentile must be in the interval (0.0, 100.0]"); + Utils.checkArgument(value >= 0, "value must be non-negative"); + return new AutoValue_Summary_Snapshot_ValueAtPercentile(percentile, value); + } + } + } + + private static void checkCountAndSum(@Nullable Long count, @Nullable Double sum) { + Utils.checkArgument(count == null || count >= 0, "count must be non-negative."); + Utils.checkArgument(sum == null || sum >= 0, "sum must be non-negative."); + if (count != null && count == 0) { + Utils.checkArgument(sum == null || sum == 0, "sum must be 0 if count is 0."); + } + } +} diff --git a/api/src/main/java/io/opencensus/metrics/export/TimeSeries.java b/api/src/main/java/io/opencensus/metrics/export/TimeSeries.java new file mode 100644 index 00000000..959f55ba --- /dev/null +++ b/api/src/main/java/io/opencensus/metrics/export/TimeSeries.java @@ -0,0 +1,96 @@ +/* + * Copyright 2018, OpenCensus Authors + * + * 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 + * + * http://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.opencensus.metrics.export; + +import com.google.auto.value.AutoValue; +import io.opencensus.common.ExperimentalApi; +import io.opencensus.common.Timestamp; +import io.opencensus.internal.Utils; +import io.opencensus.metrics.LabelKey; +import io.opencensus.metrics.LabelValue; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import javax.annotation.Nullable; +import javax.annotation.concurrent.Immutable; + +/** + * A collection of data points that describes the time-varying values of a {@code Metric}. + * + * @since 0.17 + */ +@ExperimentalApi +@Immutable +@AutoValue +public abstract class TimeSeries { + + TimeSeries() {} + + /** + * Creates a {@link TimeSeries}. + * + * @param labelValues the {@code LabelValue}s that uniquely identify this {@code TimeSeries}. + * @param points the data {@code Point}s of this {@code TimeSeries}. + * @param startTimestamp the start {@code Timestamp} of this {@code TimeSeries}. Must be non-null + * for cumulative {@code Point}s. + * @return a {@code TimeSeries}. + * @since 0.17 + */ + public static TimeSeries create( + List labelValues, List points, @Nullable Timestamp startTimestamp) { + // Fail fast on null lists to prevent NullPointerException when copying the lists. + Utils.checkNotNull(labelValues, "labelValues"); + Utils.checkNotNull(points, "points"); + Utils.checkListElementNotNull(labelValues, "labelValue"); + Utils.checkListElementNotNull(points, "point"); + return new AutoValue_TimeSeries( + Collections.unmodifiableList(new ArrayList(labelValues)), + Collections.unmodifiableList(new ArrayList(points)), + startTimestamp); + } + + /** + * Returns the set of {@link LabelValue}s that uniquely identify this {@link TimeSeries}. + * + *

Apply to all {@link Point}s. + * + *

The order of {@link LabelValue}s must match that of {@link LabelKey}s in the {@code + * MetricDescriptor}. + * + * @return the {@code LabelValue}s. + * @since 0.17 + */ + public abstract List getLabelValues(); + + /** + * Returns the data {@link Point}s of this {@link TimeSeries}. + * + * @return the data {@code Point}s. + * @since 0.17 + */ + public abstract List getPoints(); + + /** + * Returns the start {@link Timestamp} of this {@link TimeSeries} if the {@link Point}s are + * cumulative, or {@code null} if the {@link Point}s are gauge. + * + * @return the start {@code Timestamp} or {@code null}. + * @since 0.17 + */ + @Nullable + public abstract Timestamp getStartTimestamp(); +} diff --git a/api/src/main/java/io/opencensus/metrics/export/Value.java b/api/src/main/java/io/opencensus/metrics/export/Value.java new file mode 100644 index 00000000..00a939c0 --- /dev/null +++ b/api/src/main/java/io/opencensus/metrics/export/Value.java @@ -0,0 +1,246 @@ +/* + * Copyright 2018, OpenCensus Authors + * + * 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 + * + * http://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.opencensus.metrics.export; + +import com.google.auto.value.AutoValue; +import io.opencensus.common.ExperimentalApi; +import io.opencensus.common.Function; +import javax.annotation.concurrent.Immutable; + +/** + * The actual point value for a {@link Point}. + * + *

Currently there are three types of {@link Value}: + * + *

    + *
  • {@code double} + *
  • {@code long} + *
  • {@link Distribution} + *
+ * + *

Each {@link Point} contains exactly one of the three {@link Value} types. + * + * @since 0.17 + */ +@ExperimentalApi +@Immutable +public abstract class Value { + + Value() {} + + /** + * Returns a double {@link Value}. + * + * @param value value in double. + * @return a double {@code Value}. + * @since 0.17 + */ + public static Value doubleValue(double value) { + return ValueDouble.create(value); + } + + /** + * Returns a long {@link Value}. + * + * @param value value in long. + * @return a long {@code Value}. + * @since 0.17 + */ + public static Value longValue(long value) { + return ValueLong.create(value); + } + + /** + * Returns a {@link Distribution} {@link Value}. + * + * @param value value in {@link Distribution}. + * @return a {@code Distribution} {@code Value}. + * @since 0.17 + */ + public static Value distributionValue(Distribution value) { + return ValueDistribution.create(value); + } + + /** + * Returns a {@link Summary} {@link Value}. + * + * @param value value in {@link Summary}. + * @return a {@code Summary} {@code Value}. + * @since 0.17 + */ + public static Value summaryValue(Summary value) { + return ValueSummary.create(value); + } + + /** + * Applies the given match function to the underlying data type. + * + * @since 0.17 + */ + public abstract T match( + Function doubleFunction, + Function longFunction, + Function distributionFunction, + Function summaryFunction, + Function defaultFunction); + + /** A 64-bit double-precision floating-point {@link Value}. */ + @AutoValue + @Immutable + abstract static class ValueDouble extends Value { + + ValueDouble() {} + + @Override + public final T match( + Function doubleFunction, + Function longFunction, + Function distributionFunction, + Function summaryFunction, + Function defaultFunction) { + return doubleFunction.apply(getValue()); + } + + /** + * Creates a {@link ValueDouble}. + * + * @param value the value in double. + * @return a {@code ValueDouble}. + */ + static ValueDouble create(double value) { + return new AutoValue_Value_ValueDouble(value); + } + + /** + * Returns the double value. + * + * @return the double value. + */ + abstract double getValue(); + } + + /** A 64-bit integer {@link Value}. */ + @AutoValue + @Immutable + abstract static class ValueLong extends Value { + + ValueLong() {} + + @Override + public final T match( + Function doubleFunction, + Function longFunction, + Function distributionFunction, + Function summaryFunction, + Function defaultFunction) { + return longFunction.apply(getValue()); + } + + /** + * Creates a {@link ValueLong}. + * + * @param value the value in long. + * @return a {@code ValueLong}. + */ + static ValueLong create(long value) { + return new AutoValue_Value_ValueLong(value); + } + + /** + * Returns the long value. + * + * @return the long value. + */ + abstract long getValue(); + } + + /** + * {@link ValueDistribution} contains summary statistics for a population of values. It optionally + * contains a histogram representing the distribution of those values across a set of buckets. + */ + @AutoValue + @Immutable + abstract static class ValueDistribution extends Value { + + ValueDistribution() {} + + @Override + public final T match( + Function doubleFunction, + Function longFunction, + Function distributionFunction, + Function summaryFunction, + Function defaultFunction) { + return distributionFunction.apply(getValue()); + } + + /** + * Creates a {@link ValueDistribution}. + * + * @param value the {@link Distribution} value. + * @return a {@code ValueDistribution}. + */ + static ValueDistribution create(Distribution value) { + return new AutoValue_Value_ValueDistribution(value); + } + + /** + * Returns the {@link Distribution} value. + * + * @return the {@code Distribution} value. + */ + abstract Distribution getValue(); + } + + /** + * {@link ValueSummary} contains a snapshot representing values calculated over an arbitrary time + * window. + */ + @AutoValue + @Immutable + abstract static class ValueSummary extends Value { + + ValueSummary() {} + + @Override + public final T match( + Function doubleFunction, + Function longFunction, + Function distributionFunction, + Function summaryFunction, + Function defaultFunction) { + return summaryFunction.apply(getValue()); + } + + /** + * Creates a {@link ValueSummary}. + * + * @param value the {@link Summary} value. + * @return a {@code ValueSummary}. + */ + static ValueSummary create(Summary value) { + return new AutoValue_Value_ValueSummary(value); + } + + /** + * Returns the {@link Summary} value. + * + * @return the {@code Summary} value. + */ + abstract Summary getValue(); + } +} diff --git a/api/src/test/java/io/opencensus/metrics/DistributionTest.java b/api/src/test/java/io/opencensus/metrics/DistributionTest.java deleted file mode 100644 index 5ee88dd6..00000000 --- a/api/src/test/java/io/opencensus/metrics/DistributionTest.java +++ /dev/null @@ -1,227 +0,0 @@ -/* - * Copyright 2018, OpenCensus Authors - * - * 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 - * - * http://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.opencensus.metrics; - -import static com.google.common.truth.Truth.assertThat; - -import com.google.common.testing.EqualsTester; -import io.opencensus.common.Timestamp; -import io.opencensus.metrics.Distribution.Bucket; -import io.opencensus.metrics.Distribution.Exemplar; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; -import java.util.Map; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; -import org.junit.runner.RunWith; -import org.junit.runners.JUnit4; - -/** Unit tests for {@link Distribution}. */ -@RunWith(JUnit4.class) -public class DistributionTest { - - @Rule public final ExpectedException thrown = ExpectedException.none(); - - private static final Timestamp TIMESTAMP = Timestamp.create(1, 0); - private static final Map ATTACHMENTS = Collections.singletonMap("key", "value"); - private static final double TOLERANCE = 1e-6; - - @Test - public void createAndGet_Bucket() { - Bucket bucket = Bucket.create(98); - assertThat(bucket.getCount()).isEqualTo(98); - assertThat(bucket.getExemplar()).isNull(); - } - - @Test - public void createAndGet_BucketWithExemplar() { - Exemplar exemplar = Exemplar.create(12.2, TIMESTAMP, ATTACHMENTS); - Bucket bucket = Bucket.create(7, exemplar); - assertThat(bucket.getCount()).isEqualTo(7); - assertThat(bucket.getExemplar()).isEqualTo(exemplar); - } - - @Test - public void createBucket_preventNullExemplar() { - thrown.expect(NullPointerException.class); - thrown.expectMessage("exemplar"); - Bucket.create(1, null); - } - - @Test - public void createAndGet_Exemplar() { - Exemplar exemplar = Exemplar.create(-9.9, TIMESTAMP, ATTACHMENTS); - assertThat(exemplar.getValue()).isWithin(TOLERANCE).of(-9.9); - assertThat(exemplar.getTimestamp()).isEqualTo(TIMESTAMP); - assertThat(exemplar.getAttachments()).isEqualTo(ATTACHMENTS); - } - - @Test - public void createAndGet_Distribution() { - Exemplar exemplar = Exemplar.create(15.0, TIMESTAMP, ATTACHMENTS); - List bucketBounds = Arrays.asList(-1.0, 0.0, 1.0); - List buckets = - Arrays.asList( - Bucket.create(3), Bucket.create(1), Bucket.create(2), Bucket.create(4, exemplar)); - Distribution distribution = Distribution.create(10, 6.6, 678.54, bucketBounds, buckets); - assertThat(distribution.getCount()).isEqualTo(10); - assertThat(distribution.getSum()).isWithin(TOLERANCE).of(6.6); - assertThat(distribution.getSumOfSquaredDeviations()).isWithin(TOLERANCE).of(678.54); - assertThat(distribution.getBucketBoundaries()) - .containsExactlyElementsIn(bucketBounds) - .inOrder(); - assertThat(distribution.getBuckets()).containsExactlyElementsIn(buckets).inOrder(); - } - - @Test - public void createBucket_NegativeCount() { - thrown.expect(IllegalArgumentException.class); - thrown.expectMessage("bucket count should be non-negative."); - Bucket.create(-5); - } - - @Test - public void createExemplar_PreventNullAttachments() { - thrown.expect(NullPointerException.class); - thrown.expectMessage("attachments"); - Exemplar.create(15, TIMESTAMP, null); - } - - @Test - public void createExemplar_PreventNullAttachmentKey() { - Map attachments = Collections.singletonMap(null, "value"); - thrown.expect(NullPointerException.class); - thrown.expectMessage("key of attachment"); - Exemplar.create(15, TIMESTAMP, attachments); - } - - @Test - public void createExemplar_PreventNullAttachmentValue() { - Map attachments = Collections.singletonMap("key", null); - thrown.expect(NullPointerException.class); - thrown.expectMessage("value of attachment"); - Exemplar.create(15, TIMESTAMP, attachments); - } - - @Test - public void createDistribution_NegativeCount() { - List bucketBounds = Arrays.asList(-1.0, 0.0, 1.0); - List buckets = - Arrays.asList(Bucket.create(3), Bucket.create(1), Bucket.create(2), Bucket.create(4)); - thrown.expect(IllegalArgumentException.class); - thrown.expectMessage("count should be non-negative."); - Distribution.create(-10, 6.6, 678.54, bucketBounds, buckets); - } - - @Test - public void createDistribution_NegativeSumOfSquaredDeviations() { - List bucketBounds = Arrays.asList(-1.0, 0.0, 1.0); - List buckets = - Arrays.asList(Bucket.create(0), Bucket.create(0), Bucket.create(0), Bucket.create(0)); - thrown.expect(IllegalArgumentException.class); - thrown.expectMessage("sum of squared deviations should be non-negative."); - Distribution.create(0, 6.6, -678.54, bucketBounds, buckets); - } - - @Test - public void createDistribution_ZeroCountAndPositiveMean() { - List bucketBounds = Arrays.asList(-1.0, 0.0, 1.0); - List buckets = - Arrays.asList(Bucket.create(0), Bucket.create(0), Bucket.create(0), Bucket.create(0)); - thrown.expect(IllegalArgumentException.class); - thrown.expectMessage("sum should be 0 if count is 0."); - Distribution.create(0, 6.6, 0, bucketBounds, buckets); - } - - @Test - public void createDistribution_ZeroCountAndSumOfSquaredDeviations() { - List bucketBounds = Arrays.asList(-1.0, 0.0, 1.0); - List buckets = - Arrays.asList(Bucket.create(0), Bucket.create(0), Bucket.create(0), Bucket.create(0)); - thrown.expect(IllegalArgumentException.class); - thrown.expectMessage("sum of squared deviations should be 0 if count is 0."); - Distribution.create(0, 0, 678.54, bucketBounds, buckets); - } - - @Test - public void createDistribution_NullBucketBounds() { - List buckets = - Arrays.asList(Bucket.create(3), Bucket.create(1), Bucket.create(2), Bucket.create(4)); - thrown.expect(NullPointerException.class); - thrown.expectMessage("bucketBoundaries list should not be null."); - Distribution.create(10, 6.6, 678.54, null, buckets); - } - - @Test - public void createDistribution_UnorderedBucketBounds() { - List bucketBounds = Arrays.asList(0.0, -1.0, 1.0); - List buckets = - Arrays.asList(Bucket.create(3), Bucket.create(1), Bucket.create(2), Bucket.create(4)); - thrown.expect(IllegalArgumentException.class); - thrown.expectMessage("bucket boundaries not sorted."); - Distribution.create(10, 6.6, 678.54, bucketBounds, buckets); - } - - @Test - public void createDistribution_NullBucketList() { - List bucketBounds = Arrays.asList(-1.0, 0.0, 1.0); - thrown.expect(NullPointerException.class); - thrown.expectMessage("bucket list should not be null."); - Distribution.create(10, 6.6, 678.54, bucketBounds, null); - } - - @Test - public void createDistribution_NullBucket() { - List bucketBounds = Arrays.asList(-1.0, 0.0, 1.0); - List buckets = - Arrays.asList(Bucket.create(3), Bucket.create(1), null, Bucket.create(4)); - thrown.expect(NullPointerException.class); - thrown.expectMessage("bucket should not be null."); - Distribution.create(10, 6.6, 678.54, bucketBounds, buckets); - } - - @Test - public void testEquals() { - new EqualsTester() - .addEqualityGroup( - Distribution.create( - 10, - 10, - 1, - Arrays.asList(-5.0, 0.0, 5.0), - Arrays.asList( - Bucket.create(3), Bucket.create(1), Bucket.create(2), Bucket.create(4))), - Distribution.create( - 10, - 10, - 1, - Arrays.asList(-5.0, 0.0, 5.0), - Arrays.asList( - Bucket.create(3), Bucket.create(1), Bucket.create(2), Bucket.create(4)))) - .addEqualityGroup( - Distribution.create( - 7, - 10, - 23.456, - Arrays.asList(-5.0, 0.0, 5.0), - Arrays.asList( - Bucket.create(3), Bucket.create(1), Bucket.create(2), Bucket.create(4)))) - .testEquals(); - } -} diff --git a/api/src/test/java/io/opencensus/metrics/MetricDescriptorTest.java b/api/src/test/java/io/opencensus/metrics/MetricDescriptorTest.java deleted file mode 100644 index 9c0a42fc..00000000 --- a/api/src/test/java/io/opencensus/metrics/MetricDescriptorTest.java +++ /dev/null @@ -1,102 +0,0 @@ -/* - * Copyright 2018, OpenCensus Authors - * - * 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 - * - * http://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.opencensus.metrics; - -import static com.google.common.truth.Truth.assertThat; - -import com.google.common.testing.EqualsTester; -import io.opencensus.metrics.MetricDescriptor.Type; -import java.util.Arrays; -import java.util.List; -import org.hamcrest.CoreMatchers; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; -import org.junit.runner.RunWith; -import org.junit.runners.JUnit4; - -/** Unit tests for {@link MetricDescriptor}. */ -@RunWith(JUnit4.class) -public class MetricDescriptorTest { - - @Rule public final ExpectedException thrown = ExpectedException.none(); - - private static final String METRIC_NAME_1 = "metric1"; - private static final String METRIC_NAME_2 = "metric2"; - private static final String DESCRIPTION = "Metric description."; - private static final String UNIT = "kb/s"; - private static final LabelKey KEY_1 = LabelKey.create("key1", "some key"); - private static final LabelKey KEY_2 = LabelKey.create("key2", "some other key"); - - @Test - public void testGet() { - MetricDescriptor metricDescriptor = - MetricDescriptor.create( - METRIC_NAME_1, DESCRIPTION, UNIT, Type.GAUGE_DOUBLE, Arrays.asList(KEY_1, KEY_2)); - assertThat(metricDescriptor.getName()).isEqualTo(METRIC_NAME_1); - assertThat(metricDescriptor.getDescription()).isEqualTo(DESCRIPTION); - assertThat(metricDescriptor.getUnit()).isEqualTo(UNIT); - assertThat(metricDescriptor.getType()).isEqualTo(Type.GAUGE_DOUBLE); - assertThat(metricDescriptor.getLabelKeys()).containsExactly(KEY_1, KEY_2).inOrder(); - } - - @Test - public void preventNullLabelKeyList() { - thrown.expect(NullPointerException.class); - thrown.expectMessage(CoreMatchers.equalTo("labelKeys")); - MetricDescriptor.create(METRIC_NAME_1, DESCRIPTION, UNIT, Type.GAUGE_DOUBLE, null); - } - - @Test - public void preventNullLabelKey() { - List keys = Arrays.asList(KEY_1, null); - thrown.expect(NullPointerException.class); - thrown.expectMessage(CoreMatchers.equalTo("labelKey")); - MetricDescriptor.create(METRIC_NAME_1, DESCRIPTION, UNIT, Type.GAUGE_DOUBLE, keys); - } - - @Test - public void testEquals() { - new EqualsTester() - .addEqualityGroup( - MetricDescriptor.create( - METRIC_NAME_1, DESCRIPTION, UNIT, Type.GAUGE_DOUBLE, Arrays.asList(KEY_1, KEY_2)), - MetricDescriptor.create( - METRIC_NAME_1, DESCRIPTION, UNIT, Type.GAUGE_DOUBLE, Arrays.asList(KEY_1, KEY_2))) - .addEqualityGroup( - MetricDescriptor.create( - METRIC_NAME_2, DESCRIPTION, UNIT, Type.GAUGE_DOUBLE, Arrays.asList(KEY_1, KEY_2))) - .addEqualityGroup( - MetricDescriptor.create( - METRIC_NAME_2, DESCRIPTION, UNIT, Type.GAUGE_INT64, Arrays.asList(KEY_1, KEY_2))) - .addEqualityGroup( - MetricDescriptor.create( - METRIC_NAME_1, - DESCRIPTION, - UNIT, - Type.CUMULATIVE_DISTRIBUTION, - Arrays.asList(KEY_1, KEY_2))) - .addEqualityGroup( - MetricDescriptor.create( - METRIC_NAME_1, - DESCRIPTION, - UNIT, - Type.CUMULATIVE_DISTRIBUTION, - Arrays.asList(KEY_1))) - .testEquals(); - } -} diff --git a/api/src/test/java/io/opencensus/metrics/MetricTest.java b/api/src/test/java/io/opencensus/metrics/MetricTest.java deleted file mode 100644 index 37deed4b..00000000 --- a/api/src/test/java/io/opencensus/metrics/MetricTest.java +++ /dev/null @@ -1,116 +0,0 @@ -/* - * Copyright 2018, OpenCensus Authors - * - * 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 - * - * http://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.opencensus.metrics; - -import static com.google.common.truth.Truth.assertThat; - -import com.google.common.testing.EqualsTester; -import io.opencensus.common.Timestamp; -import io.opencensus.metrics.MetricDescriptor.Type; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; -import org.junit.runner.RunWith; -import org.junit.runners.JUnit4; - -/** Unit tests for {@link Metric}. */ -@RunWith(JUnit4.class) -public class MetricTest { - - @Rule public final ExpectedException thrown = ExpectedException.none(); - - private static final String METRIC_NAME_1 = "metric1"; - private static final String METRIC_NAME_2 = "metric2"; - private static final String DESCRIPTION = "Metric description."; - private static final String UNIT = "kb/s"; - private static final LabelKey KEY_1 = LabelKey.create("key1", "some key"); - private static final LabelKey KEY_2 = LabelKey.create("key1", "some other key"); - private static final MetricDescriptor METRIC_DESCRIPTOR_1 = - MetricDescriptor.create( - METRIC_NAME_1, DESCRIPTION, UNIT, Type.GAUGE_DOUBLE, Arrays.asList(KEY_1, KEY_2)); - private static final MetricDescriptor METRIC_DESCRIPTOR_2 = - MetricDescriptor.create( - METRIC_NAME_2, DESCRIPTION, UNIT, Type.CUMULATIVE_INT64, Arrays.asList(KEY_1)); - private static final LabelValue LABEL_VALUE_1 = LabelValue.create("value1"); - private static final LabelValue LABEL_VALUE_2 = LabelValue.create("value1"); - private static final LabelValue LABEL_VALUE_EMPTY = LabelValue.create(""); - private static final Value VALUE_LONG = Value.longValue(12345678); - private static final Value VALUE_DOUBLE_1 = Value.doubleValue(-345.77); - private static final Value VALUE_DOUBLE_2 = Value.doubleValue(133.79); - private static final Timestamp TIMESTAMP_1 = Timestamp.fromMillis(1000); - private static final Timestamp TIMESTAMP_2 = Timestamp.fromMillis(2000); - private static final Timestamp TIMESTAMP_3 = Timestamp.fromMillis(3000); - private static final Point POINT_1 = Point.create(VALUE_DOUBLE_1, TIMESTAMP_2); - private static final Point POINT_2 = Point.create(VALUE_DOUBLE_2, TIMESTAMP_3); - private static final Point POINT_3 = Point.create(VALUE_LONG, TIMESTAMP_3); - private static final TimeSeries GAUGE_TIME_SERIES_1 = - TimeSeries.create(Arrays.asList(LABEL_VALUE_1, LABEL_VALUE_2), Arrays.asList(POINT_1), null); - private static final TimeSeries GAUGE_TIME_SERIES_2 = - TimeSeries.create(Arrays.asList(LABEL_VALUE_1, LABEL_VALUE_2), Arrays.asList(POINT_2), null); - private static final TimeSeries CUMULATIVE_TIME_SERIES = - TimeSeries.create(Arrays.asList(LABEL_VALUE_EMPTY), Arrays.asList(POINT_3), TIMESTAMP_1); - - @Test - public void testGet() { - Metric metric = - Metric.create(METRIC_DESCRIPTOR_1, Arrays.asList(GAUGE_TIME_SERIES_1, GAUGE_TIME_SERIES_2)); - assertThat(metric.getMetricDescriptor()).isEqualTo(METRIC_DESCRIPTOR_1); - assertThat(metric.getTimeSeriesList()) - .containsExactly(GAUGE_TIME_SERIES_1, GAUGE_TIME_SERIES_2) - .inOrder(); - } - - @Test - public void typeMismatch_GaugeDouble_Long() { - typeMismatch( - METRIC_DESCRIPTOR_1, - Arrays.asList(CUMULATIVE_TIME_SERIES), - String.format("Type mismatch: %s, %s.", Type.GAUGE_DOUBLE, "ValueLong")); - } - - @Test - public void typeMismatch_CumulativeInt64_Double() { - typeMismatch( - METRIC_DESCRIPTOR_2, - Arrays.asList(GAUGE_TIME_SERIES_1), - String.format("Type mismatch: %s, %s.", Type.CUMULATIVE_INT64, "ValueDouble")); - } - - private void typeMismatch( - MetricDescriptor metricDescriptor, List timeSeriesList, String errorMessage) { - thrown.expect(IllegalArgumentException.class); - thrown.expectMessage(errorMessage); - Metric.create(metricDescriptor, timeSeriesList); - } - - @Test - public void testEquals() { - new EqualsTester() - .addEqualityGroup( - Metric.create( - METRIC_DESCRIPTOR_1, Arrays.asList(GAUGE_TIME_SERIES_1, GAUGE_TIME_SERIES_2)), - Metric.create( - METRIC_DESCRIPTOR_1, Arrays.asList(GAUGE_TIME_SERIES_1, GAUGE_TIME_SERIES_2))) - .addEqualityGroup(Metric.create(METRIC_DESCRIPTOR_1, Collections.emptyList())) - .addEqualityGroup(Metric.create(METRIC_DESCRIPTOR_2, Arrays.asList(CUMULATIVE_TIME_SERIES))) - .addEqualityGroup(Metric.create(METRIC_DESCRIPTOR_2, Collections.emptyList())) - .testEquals(); - } -} diff --git a/api/src/test/java/io/opencensus/metrics/PointTest.java b/api/src/test/java/io/opencensus/metrics/PointTest.java deleted file mode 100644 index 708814c5..00000000 --- a/api/src/test/java/io/opencensus/metrics/PointTest.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright 2018, OpenCensus Authors - * - * 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 - * - * http://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.opencensus.metrics; - -import static com.google.common.truth.Truth.assertThat; - -import com.google.common.testing.EqualsTester; -import io.opencensus.common.Timestamp; -import io.opencensus.metrics.Distribution.Bucket; -import java.util.Arrays; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.JUnit4; - -/** Unit tests for {@link Point}. */ -@RunWith(JUnit4.class) -public class PointTest { - - private static final Value DOUBLE_VALUE = Value.doubleValue(55.5); - private static final Value LONG_VALUE = Value.longValue(9876543210L); - private static final Value DISTRIBUTION_VALUE = - Value.distributionValue( - Distribution.create( - 10, - 6.6, - 678.54, - Arrays.asList(-1.0, 0.0, 1.0), - Arrays.asList( - Bucket.create(3), Bucket.create(1), Bucket.create(2), Bucket.create(4)))); - private static final Timestamp TIMESTAMP_1 = Timestamp.create(1, 2); - private static final Timestamp TIMESTAMP_2 = Timestamp.create(3, 4); - private static final Timestamp TIMESTAMP_3 = Timestamp.create(5, 6); - - @Test - public void testGet() { - Point point = Point.create(DOUBLE_VALUE, TIMESTAMP_1); - assertThat(point.getValue()).isEqualTo(DOUBLE_VALUE); - assertThat(point.getTimestamp()).isEqualTo(TIMESTAMP_1); - } - - @Test - public void testEquals() { - new EqualsTester() - .addEqualityGroup( - Point.create(DOUBLE_VALUE, TIMESTAMP_1), Point.create(DOUBLE_VALUE, TIMESTAMP_1)) - .addEqualityGroup(Point.create(LONG_VALUE, TIMESTAMP_1)) - .addEqualityGroup(Point.create(LONG_VALUE, TIMESTAMP_2)) - .addEqualityGroup( - Point.create(DISTRIBUTION_VALUE, TIMESTAMP_2), - Point.create(DISTRIBUTION_VALUE, TIMESTAMP_2)) - .addEqualityGroup(Point.create(DISTRIBUTION_VALUE, TIMESTAMP_3)) - .testEquals(); - } -} diff --git a/api/src/test/java/io/opencensus/metrics/SummaryTest.java b/api/src/test/java/io/opencensus/metrics/SummaryTest.java deleted file mode 100644 index 0b70d94e..00000000 --- a/api/src/test/java/io/opencensus/metrics/SummaryTest.java +++ /dev/null @@ -1,189 +0,0 @@ -/* - * Copyright 2018, OpenCensus Authors - * - * 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 - * - * http://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.opencensus.metrics; - -import static com.google.common.truth.Truth.assertThat; - -import com.google.common.testing.EqualsTester; -import io.opencensus.metrics.Summary.Snapshot; -import io.opencensus.metrics.Summary.Snapshot.ValueAtPercentile; -import java.util.Collections; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; -import org.junit.runner.RunWith; -import org.junit.runners.JUnit4; - -/** Unit tests for {@link Summary}. */ -@RunWith(JUnit4.class) -public class SummaryTest { - - @Rule public final ExpectedException thrown = ExpectedException.none(); - private static final double TOLERANCE = 1e-6; - - @Test - public void createAndGet_ValueAtPercentile() { - ValueAtPercentile valueAtPercentile = ValueAtPercentile.create(99.5, 10.2); - assertThat(valueAtPercentile.getPercentile()).isWithin(TOLERANCE).of(99.5); - assertThat(valueAtPercentile.getValue()).isWithin(TOLERANCE).of(10.2); - } - - @Test - public void createValueAtPercentile_InvalidValueAtPercentileInterval() { - thrown.expect(IllegalArgumentException.class); - thrown.expectMessage("percentile must be in the interval (0.0, 100.0]"); - ValueAtPercentile.create(100.1, 10.2); - } - - @Test - public void createValueAtPercentile_NegativeValue() { - thrown.expect(IllegalArgumentException.class); - thrown.expectMessage("value must be non-negative"); - ValueAtPercentile.create(99.5, -10.2); - } - - @Test - public void createAndGet_Snapshot() { - Snapshot snapshot = - Snapshot.create( - 10L, 87.07, Collections.singletonList(ValueAtPercentile.create(99.5, 10.2))); - assertThat(snapshot.getCount()).isEqualTo(10); - assertThat(snapshot.getSum()).isWithin(TOLERANCE).of(87.07); - assertThat(snapshot.getValueAtPercentiles()) - .containsExactly(ValueAtPercentile.create(99.5, 10.2)); - } - - @Test - public void createAndGet_Snapshot_WithNullCountAndSum() { - Snapshot snapshot = - Snapshot.create( - null, null, Collections.singletonList(ValueAtPercentile.create(99.5, 10.2))); - assertThat(snapshot.getCount()).isNull(); - assertThat(snapshot.getSum()).isNull(); - assertThat(snapshot.getValueAtPercentiles()) - .containsExactly(ValueAtPercentile.create(99.5, 10.2)); - } - - @Test - public void createSnapshot_NegativeCount() { - thrown.expect(IllegalArgumentException.class); - thrown.expectMessage("count must be non-negative"); - Snapshot.create(-10L, 87.07, Collections.singletonList(ValueAtPercentile.create(99.5, 10.2))); - } - - @Test - public void createSnapshot_NegativeSum() { - thrown.expect(IllegalArgumentException.class); - thrown.expectMessage("sum must be non-negative"); - Snapshot.create(10L, -87.07, Collections.singletonList(ValueAtPercentile.create(99.5, 10.2))); - } - - @Test - public void createSnapshot_ZeroCountAndNonZeroSum() { - thrown.expect(IllegalArgumentException.class); - thrown.expectMessage("sum must be 0 if count is 0"); - Snapshot.create(0L, 87.07, Collections.singletonList(ValueAtPercentile.create(99.5, 10.2))); - } - - @Test - public void createSnapshot_NullValueAtPercentilesList() { - thrown.expect(NullPointerException.class); - thrown.expectMessage("valueAtPercentiles"); - Snapshot.create(10L, 87.07, null); - } - - @Test - public void createSnapshot_OneNullValueAtPercentile() { - thrown.expect(NullPointerException.class); - thrown.expectMessage("value in valueAtPercentiles"); - Snapshot.create(10L, 87.07, Collections.singletonList(null)); - } - - @Test - public void createAndGet_Summary() { - Snapshot snapshot = - Snapshot.create( - 10L, 87.07, Collections.singletonList(ValueAtPercentile.create(99.5, 10.2))); - Summary summary = Summary.create(10L, 6.6, snapshot); - assertThat(summary.getCount()).isEqualTo(10); - assertThat(summary.getSum()).isWithin(TOLERANCE).of(6.6); - assertThat(summary.getSnapshot()).isEqualTo(snapshot); - } - - @Test - public void createSummary_NegativeCount() { - thrown.expect(IllegalArgumentException.class); - thrown.expectMessage("count must be non-negative"); - Summary.create( - -10L, 6.6, Snapshot.create(null, null, Collections.emptyList())); - } - - @Test - public void createSummary_NegativeSum() { - thrown.expect(IllegalArgumentException.class); - thrown.expectMessage("sum must be non-negative"); - Summary.create( - 10L, -6.6, Snapshot.create(null, null, Collections.emptyList())); - } - - @Test - public void createSummary_ZeroCountAndNonZeroSum() { - thrown.expect(IllegalArgumentException.class); - thrown.expectMessage("sum must be 0 if count is 0"); - Summary.create( - 0L, 6.6, Snapshot.create(null, null, Collections.emptyList())); - } - - @Test - public void createSummary_NullSnapshot() { - thrown.expect(NullPointerException.class); - thrown.expectMessage("snapshot"); - Summary.create(10L, 6.6, null); - } - - @Test - public void testEquals() { - new EqualsTester() - .addEqualityGroup( - Summary.create( - 10L, - 10.0, - Snapshot.create( - 10L, 87.07, Collections.singletonList(ValueAtPercentile.create(99.5, 10.2)))), - Summary.create( - 10L, - 10.0, - Snapshot.create( - 10L, 87.07, Collections.singletonList(ValueAtPercentile.create(99.5, 10.2))))) - .addEqualityGroup( - Summary.create( - 7L, - 10.0, - Snapshot.create( - 10L, 87.07, Collections.singletonList(ValueAtPercentile.create(99.5, 10.2))))) - .addEqualityGroup( - Summary.create( - 10L, - 7.0, - Snapshot.create( - 10L, 87.07, Collections.singletonList(ValueAtPercentile.create(99.5, 10.2))))) - .addEqualityGroup( - Summary.create( - 10L, 10.0, Snapshot.create(null, null, Collections.emptyList()))) - .testEquals(); - } -} diff --git a/api/src/test/java/io/opencensus/metrics/TimeSeriesTest.java b/api/src/test/java/io/opencensus/metrics/TimeSeriesTest.java deleted file mode 100644 index 07dff97d..00000000 --- a/api/src/test/java/io/opencensus/metrics/TimeSeriesTest.java +++ /dev/null @@ -1,116 +0,0 @@ -/* - * Copyright 2018, OpenCensus Authors - * - * 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 - * - * http://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.opencensus.metrics; - -import static com.google.common.truth.Truth.assertThat; - -import com.google.common.testing.EqualsTester; -import io.opencensus.common.Timestamp; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; -import org.hamcrest.CoreMatchers; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; -import org.junit.runner.RunWith; -import org.junit.runners.JUnit4; - -/** Unit tests for {@link TimeSeries}. */ -@RunWith(JUnit4.class) -public class TimeSeriesTest { - - @Rule public ExpectedException thrown = ExpectedException.none(); - - private static final LabelValue LABEL_VALUE_1 = LabelValue.create("value1"); - private static final LabelValue LABEL_VALUE_2 = LabelValue.create("value2"); - private static final Value VALUE_LONG = Value.longValue(12345678); - private static final Value VALUE_DOUBLE = Value.doubleValue(-345.77); - private static final Timestamp TIMESTAMP_1 = Timestamp.fromMillis(1000); - private static final Timestamp TIMESTAMP_2 = Timestamp.fromMillis(2000); - private static final Timestamp TIMESTAMP_3 = Timestamp.fromMillis(3000); - private static final Point POINT_1 = Point.create(VALUE_DOUBLE, TIMESTAMP_2); - private static final Point POINT_2 = Point.create(VALUE_LONG, TIMESTAMP_3); - - @Test - public void testGet_TimeSeries() { - TimeSeries cumulativeTimeSeries = - TimeSeries.create( - Arrays.asList(LABEL_VALUE_1, LABEL_VALUE_2), Arrays.asList(POINT_1), TIMESTAMP_1); - assertThat(cumulativeTimeSeries.getStartTimestamp()).isEqualTo(TIMESTAMP_1); - assertThat(cumulativeTimeSeries.getLabelValues()) - .containsExactly(LABEL_VALUE_1, LABEL_VALUE_2) - .inOrder(); - assertThat(cumulativeTimeSeries.getPoints()).containsExactly(POINT_1).inOrder(); - } - - @Test - public void create_WithNullLabelValueList() { - thrown.expect(NullPointerException.class); - thrown.expectMessage(CoreMatchers.equalTo("labelValues")); - TimeSeries.create(null, Collections.emptyList(), TIMESTAMP_1); - } - - @Test - public void create_WithNullLabelValue() { - List labelValues = Arrays.asList(LABEL_VALUE_1, null); - thrown.expect(NullPointerException.class); - thrown.expectMessage(CoreMatchers.equalTo("labelValue")); - TimeSeries.create(labelValues, Collections.emptyList(), TIMESTAMP_1); - } - - @Test - public void create_WithNullPointList() { - thrown.expect(NullPointerException.class); - thrown.expectMessage(CoreMatchers.equalTo("points")); - TimeSeries.create(Collections.emptyList(), null, TIMESTAMP_1); - } - - @Test - public void create_WithNullPoint() { - List points = Arrays.asList(POINT_1, null); - thrown.expect(NullPointerException.class); - thrown.expectMessage(CoreMatchers.equalTo("point")); - TimeSeries.create(Collections.emptyList(), points, TIMESTAMP_1); - } - - @Test - public void testEquals() { - new EqualsTester() - .addEqualityGroup( - TimeSeries.create( - Arrays.asList(LABEL_VALUE_1, LABEL_VALUE_2), Arrays.asList(POINT_1), TIMESTAMP_1), - TimeSeries.create( - Arrays.asList(LABEL_VALUE_1, LABEL_VALUE_2), Arrays.asList(POINT_1), TIMESTAMP_1)) - .addEqualityGroup( - TimeSeries.create( - Arrays.asList(LABEL_VALUE_1, LABEL_VALUE_2), Arrays.asList(POINT_1), null), - TimeSeries.create( - Arrays.asList(LABEL_VALUE_1, LABEL_VALUE_2), Arrays.asList(POINT_1), null)) - .addEqualityGroup( - TimeSeries.create( - Arrays.asList(LABEL_VALUE_1, LABEL_VALUE_2), Arrays.asList(POINT_1), TIMESTAMP_2)) - .addEqualityGroup( - TimeSeries.create(Arrays.asList(LABEL_VALUE_1), Arrays.asList(POINT_1), TIMESTAMP_2)) - .addEqualityGroup( - TimeSeries.create(Arrays.asList(LABEL_VALUE_1), Arrays.asList(POINT_2), TIMESTAMP_2)) - .addEqualityGroup( - TimeSeries.create( - Arrays.asList(LABEL_VALUE_1), Arrays.asList(POINT_1, POINT_2), TIMESTAMP_2)) - .testEquals(); - } -} diff --git a/api/src/test/java/io/opencensus/metrics/ValueTest.java b/api/src/test/java/io/opencensus/metrics/ValueTest.java deleted file mode 100644 index a65202a8..00000000 --- a/api/src/test/java/io/opencensus/metrics/ValueTest.java +++ /dev/null @@ -1,155 +0,0 @@ -/* - * Copyright 2018, OpenCensus Authors - * - * 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 - * - * http://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.opencensus.metrics; - -import static com.google.common.truth.Truth.assertThat; - -import com.google.common.testing.EqualsTester; -import io.opencensus.common.Function; -import io.opencensus.common.Functions; -import io.opencensus.metrics.Distribution.Bucket; -import io.opencensus.metrics.Summary.Snapshot; -import io.opencensus.metrics.Summary.Snapshot.ValueAtPercentile; -import io.opencensus.metrics.Value.ValueDistribution; -import io.opencensus.metrics.Value.ValueDouble; -import io.opencensus.metrics.Value.ValueLong; -import io.opencensus.metrics.Value.ValueSummary; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.JUnit4; - -/** Unit tests for {@link Value}. */ -@RunWith(JUnit4.class) -public class ValueTest { - private static final double TOLERANCE = 1e-6; - - private static final Distribution DISTRIBUTION = - Distribution.create( - 10, - 10, - 1, - Arrays.asList(-5.0, 0.0, 5.0), - Arrays.asList(Bucket.create(3), Bucket.create(1), Bucket.create(2), Bucket.create(4))); - private static final Summary SUMMARY = - Summary.create( - 10L, - 10.0, - Snapshot.create( - 10L, 87.07, Collections.singletonList(ValueAtPercentile.create(0.98, 10.2)))); - - @Test - public void createAndGet_ValueDouble() { - Value value = Value.doubleValue(-34.56); - assertThat(value).isInstanceOf(ValueDouble.class); - assertThat(((ValueDouble) value).getValue()).isWithin(TOLERANCE).of(-34.56); - } - - @Test - public void createAndGet_ValueLong() { - Value value = Value.longValue(123456789); - assertThat(value).isInstanceOf(ValueLong.class); - assertThat(((ValueLong) value).getValue()).isEqualTo(123456789); - } - - @Test - public void createAndGet_ValueDistribution() { - Value value = Value.distributionValue(DISTRIBUTION); - assertThat(value).isInstanceOf(ValueDistribution.class); - assertThat(((ValueDistribution) value).getValue()).isEqualTo(DISTRIBUTION); - } - - @Test - public void createAndGet_ValueSummary() { - Value value = Value.summaryValue(SUMMARY); - assertThat(value).isInstanceOf(ValueSummary.class); - assertThat(((ValueSummary) value).getValue()).isEqualTo(SUMMARY); - } - - @Test - public void testEquals() { - new EqualsTester() - .addEqualityGroup(Value.doubleValue(1.0), Value.doubleValue(1.0)) - .addEqualityGroup(Value.doubleValue(2.0)) - .addEqualityGroup(Value.longValue(1L)) - .addEqualityGroup(Value.longValue(2L)) - .addEqualityGroup( - Value.distributionValue( - Distribution.create( - 7, - 10, - 23.456, - Arrays.asList(-5.0, 0.0, 5.0), - Arrays.asList( - Bucket.create(3), Bucket.create(1), Bucket.create(2), Bucket.create(4))))) - .testEquals(); - } - - @Test - public void testMatch() { - List values = - Arrays.asList( - ValueDouble.create(1.0), - ValueLong.create(-1), - ValueDistribution.create(DISTRIBUTION), - ValueSummary.create(SUMMARY)); - List expected = - Arrays.asList(1.0, -1L, 10.0, 10L, 1.0, -5.0, 0.0, 5.0, 3L, 1L, 2L, 4L); - final List actual = new ArrayList(); - for (Value value : values) { - value.match( - new Function() { - @Override - public Object apply(Double arg) { - actual.add(arg); - return null; - } - }, - new Function() { - @Override - public Object apply(Long arg) { - actual.add(arg); - return null; - } - }, - new Function() { - @Override - public Object apply(Distribution arg) { - actual.add(arg.getSum()); - actual.add(arg.getCount()); - actual.add(arg.getSumOfSquaredDeviations()); - actual.addAll(arg.getBucketBoundaries()); - for (Bucket bucket : arg.getBuckets()) { - actual.add(bucket.getCount()); - } - return null; - } - }, - new Function() { - @Override - public Object apply(Summary arg) { - return null; - } - }, - Functions.throwAssertionError()); - } - assertThat(actual).containsExactlyElementsIn(expected).inOrder(); - } -} diff --git a/api/src/test/java/io/opencensus/metrics/export/DistributionTest.java b/api/src/test/java/io/opencensus/metrics/export/DistributionTest.java new file mode 100644 index 00000000..0be4b5d1 --- /dev/null +++ b/api/src/test/java/io/opencensus/metrics/export/DistributionTest.java @@ -0,0 +1,227 @@ +/* + * Copyright 2018, OpenCensus Authors + * + * 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 + * + * http://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.opencensus.metrics.export; + +import static com.google.common.truth.Truth.assertThat; + +import com.google.common.testing.EqualsTester; +import io.opencensus.common.Timestamp; +import io.opencensus.metrics.export.Distribution.Bucket; +import io.opencensus.metrics.export.Distribution.Exemplar; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +/** Unit tests for {@link Distribution}. */ +@RunWith(JUnit4.class) +public class DistributionTest { + + @Rule public final ExpectedException thrown = ExpectedException.none(); + + private static final Timestamp TIMESTAMP = Timestamp.create(1, 0); + private static final Map ATTACHMENTS = Collections.singletonMap("key", "value"); + private static final double TOLERANCE = 1e-6; + + @Test + public void createAndGet_Bucket() { + Bucket bucket = Bucket.create(98); + assertThat(bucket.getCount()).isEqualTo(98); + assertThat(bucket.getExemplar()).isNull(); + } + + @Test + public void createAndGet_BucketWithExemplar() { + Exemplar exemplar = Exemplar.create(12.2, TIMESTAMP, ATTACHMENTS); + Bucket bucket = Bucket.create(7, exemplar); + assertThat(bucket.getCount()).isEqualTo(7); + assertThat(bucket.getExemplar()).isEqualTo(exemplar); + } + + @Test + public void createBucket_preventNullExemplar() { + thrown.expect(NullPointerException.class); + thrown.expectMessage("exemplar"); + Bucket.create(1, null); + } + + @Test + public void createAndGet_Exemplar() { + Exemplar exemplar = Exemplar.create(-9.9, TIMESTAMP, ATTACHMENTS); + assertThat(exemplar.getValue()).isWithin(TOLERANCE).of(-9.9); + assertThat(exemplar.getTimestamp()).isEqualTo(TIMESTAMP); + assertThat(exemplar.getAttachments()).isEqualTo(ATTACHMENTS); + } + + @Test + public void createAndGet_Distribution() { + Exemplar exemplar = Exemplar.create(15.0, TIMESTAMP, ATTACHMENTS); + List bucketBounds = Arrays.asList(-1.0, 0.0, 1.0); + List buckets = + Arrays.asList( + Bucket.create(3), Bucket.create(1), Bucket.create(2), Bucket.create(4, exemplar)); + Distribution distribution = Distribution.create(10, 6.6, 678.54, bucketBounds, buckets); + assertThat(distribution.getCount()).isEqualTo(10); + assertThat(distribution.getSum()).isWithin(TOLERANCE).of(6.6); + assertThat(distribution.getSumOfSquaredDeviations()).isWithin(TOLERANCE).of(678.54); + assertThat(distribution.getBucketBoundaries()) + .containsExactlyElementsIn(bucketBounds) + .inOrder(); + assertThat(distribution.getBuckets()).containsExactlyElementsIn(buckets).inOrder(); + } + + @Test + public void createBucket_NegativeCount() { + thrown.expect(IllegalArgumentException.class); + thrown.expectMessage("bucket count should be non-negative."); + Bucket.create(-5); + } + + @Test + public void createExemplar_PreventNullAttachments() { + thrown.expect(NullPointerException.class); + thrown.expectMessage("attachments"); + Exemplar.create(15, TIMESTAMP, null); + } + + @Test + public void createExemplar_PreventNullAttachmentKey() { + Map attachments = Collections.singletonMap(null, "value"); + thrown.expect(NullPointerException.class); + thrown.expectMessage("key of attachment"); + Exemplar.create(15, TIMESTAMP, attachments); + } + + @Test + public void createExemplar_PreventNullAttachmentValue() { + Map attachments = Collections.singletonMap("key", null); + thrown.expect(NullPointerException.class); + thrown.expectMessage("value of attachment"); + Exemplar.create(15, TIMESTAMP, attachments); + } + + @Test + public void createDistribution_NegativeCount() { + List bucketBounds = Arrays.asList(-1.0, 0.0, 1.0); + List buckets = + Arrays.asList(Bucket.create(3), Bucket.create(1), Bucket.create(2), Bucket.create(4)); + thrown.expect(IllegalArgumentException.class); + thrown.expectMessage("count should be non-negative."); + Distribution.create(-10, 6.6, 678.54, bucketBounds, buckets); + } + + @Test + public void createDistribution_NegativeSumOfSquaredDeviations() { + List bucketBounds = Arrays.asList(-1.0, 0.0, 1.0); + List buckets = + Arrays.asList(Bucket.create(0), Bucket.create(0), Bucket.create(0), Bucket.create(0)); + thrown.expect(IllegalArgumentException.class); + thrown.expectMessage("sum of squared deviations should be non-negative."); + Distribution.create(0, 6.6, -678.54, bucketBounds, buckets); + } + + @Test + public void createDistribution_ZeroCountAndPositiveMean() { + List bucketBounds = Arrays.asList(-1.0, 0.0, 1.0); + List buckets = + Arrays.asList(Bucket.create(0), Bucket.create(0), Bucket.create(0), Bucket.create(0)); + thrown.expect(IllegalArgumentException.class); + thrown.expectMessage("sum should be 0 if count is 0."); + Distribution.create(0, 6.6, 0, bucketBounds, buckets); + } + + @Test + public void createDistribution_ZeroCountAndSumOfSquaredDeviations() { + List bucketBounds = Arrays.asList(-1.0, 0.0, 1.0); + List buckets = + Arrays.asList(Bucket.create(0), Bucket.create(0), Bucket.create(0), Bucket.create(0)); + thrown.expect(IllegalArgumentException.class); + thrown.expectMessage("sum of squared deviations should be 0 if count is 0."); + Distribution.create(0, 0, 678.54, bucketBounds, buckets); + } + + @Test + public void createDistribution_NullBucketBounds() { + List buckets = + Arrays.asList(Bucket.create(3), Bucket.create(1), Bucket.create(2), Bucket.create(4)); + thrown.expect(NullPointerException.class); + thrown.expectMessage("bucketBoundaries list should not be null."); + Distribution.create(10, 6.6, 678.54, null, buckets); + } + + @Test + public void createDistribution_UnorderedBucketBounds() { + List bucketBounds = Arrays.asList(0.0, -1.0, 1.0); + List buckets = + Arrays.asList(Bucket.create(3), Bucket.create(1), Bucket.create(2), Bucket.create(4)); + thrown.expect(IllegalArgumentException.class); + thrown.expectMessage("bucket boundaries not sorted."); + Distribution.create(10, 6.6, 678.54, bucketBounds, buckets); + } + + @Test + public void createDistribution_NullBucketList() { + List bucketBounds = Arrays.asList(-1.0, 0.0, 1.0); + thrown.expect(NullPointerException.class); + thrown.expectMessage("bucket list should not be null."); + Distribution.create(10, 6.6, 678.54, bucketBounds, null); + } + + @Test + public void createDistribution_NullBucket() { + List bucketBounds = Arrays.asList(-1.0, 0.0, 1.0); + List buckets = + Arrays.asList(Bucket.create(3), Bucket.create(1), null, Bucket.create(4)); + thrown.expect(NullPointerException.class); + thrown.expectMessage("bucket should not be null."); + Distribution.create(10, 6.6, 678.54, bucketBounds, buckets); + } + + @Test + public void testEquals() { + new EqualsTester() + .addEqualityGroup( + Distribution.create( + 10, + 10, + 1, + Arrays.asList(-5.0, 0.0, 5.0), + Arrays.asList( + Bucket.create(3), Bucket.create(1), Bucket.create(2), Bucket.create(4))), + Distribution.create( + 10, + 10, + 1, + Arrays.asList(-5.0, 0.0, 5.0), + Arrays.asList( + Bucket.create(3), Bucket.create(1), Bucket.create(2), Bucket.create(4)))) + .addEqualityGroup( + Distribution.create( + 7, + 10, + 23.456, + Arrays.asList(-5.0, 0.0, 5.0), + Arrays.asList( + Bucket.create(3), Bucket.create(1), Bucket.create(2), Bucket.create(4)))) + .testEquals(); + } +} diff --git a/api/src/test/java/io/opencensus/metrics/export/MetricDescriptorTest.java b/api/src/test/java/io/opencensus/metrics/export/MetricDescriptorTest.java new file mode 100644 index 00000000..502170c6 --- /dev/null +++ b/api/src/test/java/io/opencensus/metrics/export/MetricDescriptorTest.java @@ -0,0 +1,103 @@ +/* + * Copyright 2018, OpenCensus Authors + * + * 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 + * + * http://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.opencensus.metrics.export; + +import static com.google.common.truth.Truth.assertThat; + +import com.google.common.testing.EqualsTester; +import io.opencensus.metrics.LabelKey; +import io.opencensus.metrics.export.MetricDescriptor.Type; +import java.util.Arrays; +import java.util.List; +import org.hamcrest.CoreMatchers; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +/** Unit tests for {@link MetricDescriptor}. */ +@RunWith(JUnit4.class) +public class MetricDescriptorTest { + + @Rule public final ExpectedException thrown = ExpectedException.none(); + + private static final String METRIC_NAME_1 = "metric1"; + private static final String METRIC_NAME_2 = "metric2"; + private static final String DESCRIPTION = "Metric description."; + private static final String UNIT = "kb/s"; + private static final LabelKey KEY_1 = LabelKey.create("key1", "some key"); + private static final LabelKey KEY_2 = LabelKey.create("key2", "some other key"); + + @Test + public void testGet() { + MetricDescriptor metricDescriptor = + MetricDescriptor.create( + METRIC_NAME_1, DESCRIPTION, UNIT, Type.GAUGE_DOUBLE, Arrays.asList(KEY_1, KEY_2)); + assertThat(metricDescriptor.getName()).isEqualTo(METRIC_NAME_1); + assertThat(metricDescriptor.getDescription()).isEqualTo(DESCRIPTION); + assertThat(metricDescriptor.getUnit()).isEqualTo(UNIT); + assertThat(metricDescriptor.getType()).isEqualTo(Type.GAUGE_DOUBLE); + assertThat(metricDescriptor.getLabelKeys()).containsExactly(KEY_1, KEY_2).inOrder(); + } + + @Test + public void preventNullLabelKeyList() { + thrown.expect(NullPointerException.class); + thrown.expectMessage(CoreMatchers.equalTo("labelKeys")); + MetricDescriptor.create(METRIC_NAME_1, DESCRIPTION, UNIT, Type.GAUGE_DOUBLE, null); + } + + @Test + public void preventNullLabelKey() { + List keys = Arrays.asList(KEY_1, null); + thrown.expect(NullPointerException.class); + thrown.expectMessage(CoreMatchers.equalTo("labelKey")); + MetricDescriptor.create(METRIC_NAME_1, DESCRIPTION, UNIT, Type.GAUGE_DOUBLE, keys); + } + + @Test + public void testEquals() { + new EqualsTester() + .addEqualityGroup( + MetricDescriptor.create( + METRIC_NAME_1, DESCRIPTION, UNIT, Type.GAUGE_DOUBLE, Arrays.asList(KEY_1, KEY_2)), + MetricDescriptor.create( + METRIC_NAME_1, DESCRIPTION, UNIT, Type.GAUGE_DOUBLE, Arrays.asList(KEY_1, KEY_2))) + .addEqualityGroup( + MetricDescriptor.create( + METRIC_NAME_2, DESCRIPTION, UNIT, Type.GAUGE_DOUBLE, Arrays.asList(KEY_1, KEY_2))) + .addEqualityGroup( + MetricDescriptor.create( + METRIC_NAME_2, DESCRIPTION, UNIT, Type.GAUGE_INT64, Arrays.asList(KEY_1, KEY_2))) + .addEqualityGroup( + MetricDescriptor.create( + METRIC_NAME_1, + DESCRIPTION, + UNIT, + Type.CUMULATIVE_DISTRIBUTION, + Arrays.asList(KEY_1, KEY_2))) + .addEqualityGroup( + MetricDescriptor.create( + METRIC_NAME_1, + DESCRIPTION, + UNIT, + Type.CUMULATIVE_DISTRIBUTION, + Arrays.asList(KEY_1))) + .testEquals(); + } +} diff --git a/api/src/test/java/io/opencensus/metrics/export/MetricProducerManagerTest.java b/api/src/test/java/io/opencensus/metrics/export/MetricProducerManagerTest.java index 07854927..1025427f 100644 --- a/api/src/test/java/io/opencensus/metrics/export/MetricProducerManagerTest.java +++ b/api/src/test/java/io/opencensus/metrics/export/MetricProducerManagerTest.java @@ -18,7 +18,6 @@ package io.opencensus.metrics.export; import static com.google.common.truth.Truth.assertThat; -import io.opencensus.metrics.MetricProducer; import org.junit.Before; import org.junit.Rule; import org.junit.Test; diff --git a/api/src/test/java/io/opencensus/metrics/export/MetricTest.java b/api/src/test/java/io/opencensus/metrics/export/MetricTest.java new file mode 100644 index 00000000..0b1ecf65 --- /dev/null +++ b/api/src/test/java/io/opencensus/metrics/export/MetricTest.java @@ -0,0 +1,118 @@ +/* + * Copyright 2018, OpenCensus Authors + * + * 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 + * + * http://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.opencensus.metrics.export; + +import static com.google.common.truth.Truth.assertThat; + +import com.google.common.testing.EqualsTester; +import io.opencensus.common.Timestamp; +import io.opencensus.metrics.LabelKey; +import io.opencensus.metrics.LabelValue; +import io.opencensus.metrics.export.MetricDescriptor.Type; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +/** Unit tests for {@link Metric}. */ +@RunWith(JUnit4.class) +public class MetricTest { + + @Rule public final ExpectedException thrown = ExpectedException.none(); + + private static final String METRIC_NAME_1 = "metric1"; + private static final String METRIC_NAME_2 = "metric2"; + private static final String DESCRIPTION = "Metric description."; + private static final String UNIT = "kb/s"; + private static final LabelKey KEY_1 = LabelKey.create("key1", "some key"); + private static final LabelKey KEY_2 = LabelKey.create("key1", "some other key"); + private static final MetricDescriptor METRIC_DESCRIPTOR_1 = + MetricDescriptor.create( + METRIC_NAME_1, DESCRIPTION, UNIT, Type.GAUGE_DOUBLE, Arrays.asList(KEY_1, KEY_2)); + private static final MetricDescriptor METRIC_DESCRIPTOR_2 = + MetricDescriptor.create( + METRIC_NAME_2, DESCRIPTION, UNIT, Type.CUMULATIVE_INT64, Arrays.asList(KEY_1)); + private static final LabelValue LABEL_VALUE_1 = LabelValue.create("value1"); + private static final LabelValue LABEL_VALUE_2 = LabelValue.create("value1"); + private static final LabelValue LABEL_VALUE_EMPTY = LabelValue.create(""); + private static final Value VALUE_LONG = Value.longValue(12345678); + private static final Value VALUE_DOUBLE_1 = Value.doubleValue(-345.77); + private static final Value VALUE_DOUBLE_2 = Value.doubleValue(133.79); + private static final Timestamp TIMESTAMP_1 = Timestamp.fromMillis(1000); + private static final Timestamp TIMESTAMP_2 = Timestamp.fromMillis(2000); + private static final Timestamp TIMESTAMP_3 = Timestamp.fromMillis(3000); + private static final Point POINT_1 = Point.create(VALUE_DOUBLE_1, TIMESTAMP_2); + private static final Point POINT_2 = Point.create(VALUE_DOUBLE_2, TIMESTAMP_3); + private static final Point POINT_3 = Point.create(VALUE_LONG, TIMESTAMP_3); + private static final TimeSeries GAUGE_TIME_SERIES_1 = + TimeSeries.create(Arrays.asList(LABEL_VALUE_1, LABEL_VALUE_2), Arrays.asList(POINT_1), null); + private static final TimeSeries GAUGE_TIME_SERIES_2 = + TimeSeries.create(Arrays.asList(LABEL_VALUE_1, LABEL_VALUE_2), Arrays.asList(POINT_2), null); + private static final TimeSeries CUMULATIVE_TIME_SERIES = + TimeSeries.create(Arrays.asList(LABEL_VALUE_EMPTY), Arrays.asList(POINT_3), TIMESTAMP_1); + + @Test + public void testGet() { + Metric metric = + Metric.create(METRIC_DESCRIPTOR_1, Arrays.asList(GAUGE_TIME_SERIES_1, GAUGE_TIME_SERIES_2)); + assertThat(metric.getMetricDescriptor()).isEqualTo(METRIC_DESCRIPTOR_1); + assertThat(metric.getTimeSeriesList()) + .containsExactly(GAUGE_TIME_SERIES_1, GAUGE_TIME_SERIES_2) + .inOrder(); + } + + @Test + public void typeMismatch_GaugeDouble_Long() { + typeMismatch( + METRIC_DESCRIPTOR_1, + Arrays.asList(CUMULATIVE_TIME_SERIES), + String.format("Type mismatch: %s, %s.", Type.GAUGE_DOUBLE, "ValueLong")); + } + + @Test + public void typeMismatch_CumulativeInt64_Double() { + typeMismatch( + METRIC_DESCRIPTOR_2, + Arrays.asList(GAUGE_TIME_SERIES_1), + String.format("Type mismatch: %s, %s.", Type.CUMULATIVE_INT64, "ValueDouble")); + } + + private void typeMismatch( + MetricDescriptor metricDescriptor, List timeSeriesList, String errorMessage) { + thrown.expect(IllegalArgumentException.class); + thrown.expectMessage(errorMessage); + Metric.create(metricDescriptor, timeSeriesList); + } + + @Test + public void testEquals() { + new EqualsTester() + .addEqualityGroup( + Metric.create( + METRIC_DESCRIPTOR_1, Arrays.asList(GAUGE_TIME_SERIES_1, GAUGE_TIME_SERIES_2)), + Metric.create( + METRIC_DESCRIPTOR_1, Arrays.asList(GAUGE_TIME_SERIES_1, GAUGE_TIME_SERIES_2))) + .addEqualityGroup(Metric.create(METRIC_DESCRIPTOR_1, Collections.emptyList())) + .addEqualityGroup(Metric.create(METRIC_DESCRIPTOR_2, Arrays.asList(CUMULATIVE_TIME_SERIES))) + .addEqualityGroup(Metric.create(METRIC_DESCRIPTOR_2, Collections.emptyList())) + .testEquals(); + } +} diff --git a/api/src/test/java/io/opencensus/metrics/export/PointTest.java b/api/src/test/java/io/opencensus/metrics/export/PointTest.java new file mode 100644 index 00000000..da5b83dc --- /dev/null +++ b/api/src/test/java/io/opencensus/metrics/export/PointTest.java @@ -0,0 +1,68 @@ +/* + * Copyright 2018, OpenCensus Authors + * + * 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 + * + * http://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.opencensus.metrics.export; + +import static com.google.common.truth.Truth.assertThat; + +import com.google.common.testing.EqualsTester; +import io.opencensus.common.Timestamp; +import io.opencensus.metrics.export.Distribution.Bucket; +import java.util.Arrays; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +/** Unit tests for {@link Point}. */ +@RunWith(JUnit4.class) +public class PointTest { + + private static final Value DOUBLE_VALUE = Value.doubleValue(55.5); + private static final Value LONG_VALUE = Value.longValue(9876543210L); + private static final Value DISTRIBUTION_VALUE = + Value.distributionValue( + Distribution.create( + 10, + 6.6, + 678.54, + Arrays.asList(-1.0, 0.0, 1.0), + Arrays.asList( + Bucket.create(3), Bucket.create(1), Bucket.create(2), Bucket.create(4)))); + private static final Timestamp TIMESTAMP_1 = Timestamp.create(1, 2); + private static final Timestamp TIMESTAMP_2 = Timestamp.create(3, 4); + private static final Timestamp TIMESTAMP_3 = Timestamp.create(5, 6); + + @Test + public void testGet() { + Point point = Point.create(DOUBLE_VALUE, TIMESTAMP_1); + assertThat(point.getValue()).isEqualTo(DOUBLE_VALUE); + assertThat(point.getTimestamp()).isEqualTo(TIMESTAMP_1); + } + + @Test + public void testEquals() { + new EqualsTester() + .addEqualityGroup( + Point.create(DOUBLE_VALUE, TIMESTAMP_1), Point.create(DOUBLE_VALUE, TIMESTAMP_1)) + .addEqualityGroup(Point.create(LONG_VALUE, TIMESTAMP_1)) + .addEqualityGroup(Point.create(LONG_VALUE, TIMESTAMP_2)) + .addEqualityGroup( + Point.create(DISTRIBUTION_VALUE, TIMESTAMP_2), + Point.create(DISTRIBUTION_VALUE, TIMESTAMP_2)) + .addEqualityGroup(Point.create(DISTRIBUTION_VALUE, TIMESTAMP_3)) + .testEquals(); + } +} diff --git a/api/src/test/java/io/opencensus/metrics/export/SummaryTest.java b/api/src/test/java/io/opencensus/metrics/export/SummaryTest.java new file mode 100644 index 00000000..c10df043 --- /dev/null +++ b/api/src/test/java/io/opencensus/metrics/export/SummaryTest.java @@ -0,0 +1,189 @@ +/* + * Copyright 2018, OpenCensus Authors + * + * 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 + * + * http://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.opencensus.metrics.export; + +import static com.google.common.truth.Truth.assertThat; + +import com.google.common.testing.EqualsTester; +import io.opencensus.metrics.export.Summary.Snapshot; +import io.opencensus.metrics.export.Summary.Snapshot.ValueAtPercentile; +import java.util.Collections; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +/** Unit tests for {@link Summary}. */ +@RunWith(JUnit4.class) +public class SummaryTest { + + @Rule public final ExpectedException thrown = ExpectedException.none(); + private static final double TOLERANCE = 1e-6; + + @Test + public void createAndGet_ValueAtPercentile() { + ValueAtPercentile valueAtPercentile = ValueAtPercentile.create(99.5, 10.2); + assertThat(valueAtPercentile.getPercentile()).isWithin(TOLERANCE).of(99.5); + assertThat(valueAtPercentile.getValue()).isWithin(TOLERANCE).of(10.2); + } + + @Test + public void createValueAtPercentile_InvalidValueAtPercentileInterval() { + thrown.expect(IllegalArgumentException.class); + thrown.expectMessage("percentile must be in the interval (0.0, 100.0]"); + ValueAtPercentile.create(100.1, 10.2); + } + + @Test + public void createValueAtPercentile_NegativeValue() { + thrown.expect(IllegalArgumentException.class); + thrown.expectMessage("value must be non-negative"); + ValueAtPercentile.create(99.5, -10.2); + } + + @Test + public void createAndGet_Snapshot() { + Snapshot snapshot = + Snapshot.create( + 10L, 87.07, Collections.singletonList(ValueAtPercentile.create(99.5, 10.2))); + assertThat(snapshot.getCount()).isEqualTo(10); + assertThat(snapshot.getSum()).isWithin(TOLERANCE).of(87.07); + assertThat(snapshot.getValueAtPercentiles()) + .containsExactly(ValueAtPercentile.create(99.5, 10.2)); + } + + @Test + public void createAndGet_Snapshot_WithNullCountAndSum() { + Snapshot snapshot = + Snapshot.create( + null, null, Collections.singletonList(ValueAtPercentile.create(99.5, 10.2))); + assertThat(snapshot.getCount()).isNull(); + assertThat(snapshot.getSum()).isNull(); + assertThat(snapshot.getValueAtPercentiles()) + .containsExactly(ValueAtPercentile.create(99.5, 10.2)); + } + + @Test + public void createSnapshot_NegativeCount() { + thrown.expect(IllegalArgumentException.class); + thrown.expectMessage("count must be non-negative"); + Snapshot.create(-10L, 87.07, Collections.singletonList(ValueAtPercentile.create(99.5, 10.2))); + } + + @Test + public void createSnapshot_NegativeSum() { + thrown.expect(IllegalArgumentException.class); + thrown.expectMessage("sum must be non-negative"); + Snapshot.create(10L, -87.07, Collections.singletonList(ValueAtPercentile.create(99.5, 10.2))); + } + + @Test + public void createSnapshot_ZeroCountAndNonZeroSum() { + thrown.expect(IllegalArgumentException.class); + thrown.expectMessage("sum must be 0 if count is 0"); + Snapshot.create(0L, 87.07, Collections.singletonList(ValueAtPercentile.create(99.5, 10.2))); + } + + @Test + public void createSnapshot_NullValueAtPercentilesList() { + thrown.expect(NullPointerException.class); + thrown.expectMessage("valueAtPercentiles"); + Snapshot.create(10L, 87.07, null); + } + + @Test + public void createSnapshot_OneNullValueAtPercentile() { + thrown.expect(NullPointerException.class); + thrown.expectMessage("value in valueAtPercentiles"); + Snapshot.create(10L, 87.07, Collections.singletonList(null)); + } + + @Test + public void createAndGet_Summary() { + Snapshot snapshot = + Snapshot.create( + 10L, 87.07, Collections.singletonList(ValueAtPercentile.create(99.5, 10.2))); + Summary summary = Summary.create(10L, 6.6, snapshot); + assertThat(summary.getCount()).isEqualTo(10); + assertThat(summary.getSum()).isWithin(TOLERANCE).of(6.6); + assertThat(summary.getSnapshot()).isEqualTo(snapshot); + } + + @Test + public void createSummary_NegativeCount() { + thrown.expect(IllegalArgumentException.class); + thrown.expectMessage("count must be non-negative"); + Summary.create( + -10L, 6.6, Snapshot.create(null, null, Collections.emptyList())); + } + + @Test + public void createSummary_NegativeSum() { + thrown.expect(IllegalArgumentException.class); + thrown.expectMessage("sum must be non-negative"); + Summary.create( + 10L, -6.6, Snapshot.create(null, null, Collections.emptyList())); + } + + @Test + public void createSummary_ZeroCountAndNonZeroSum() { + thrown.expect(IllegalArgumentException.class); + thrown.expectMessage("sum must be 0 if count is 0"); + Summary.create( + 0L, 6.6, Snapshot.create(null, null, Collections.emptyList())); + } + + @Test + public void createSummary_NullSnapshot() { + thrown.expect(NullPointerException.class); + thrown.expectMessage("snapshot"); + Summary.create(10L, 6.6, null); + } + + @Test + public void testEquals() { + new EqualsTester() + .addEqualityGroup( + Summary.create( + 10L, + 10.0, + Snapshot.create( + 10L, 87.07, Collections.singletonList(ValueAtPercentile.create(99.5, 10.2)))), + Summary.create( + 10L, + 10.0, + Snapshot.create( + 10L, 87.07, Collections.singletonList(ValueAtPercentile.create(99.5, 10.2))))) + .addEqualityGroup( + Summary.create( + 7L, + 10.0, + Snapshot.create( + 10L, 87.07, Collections.singletonList(ValueAtPercentile.create(99.5, 10.2))))) + .addEqualityGroup( + Summary.create( + 10L, + 7.0, + Snapshot.create( + 10L, 87.07, Collections.singletonList(ValueAtPercentile.create(99.5, 10.2))))) + .addEqualityGroup( + Summary.create( + 10L, 10.0, Snapshot.create(null, null, Collections.emptyList()))) + .testEquals(); + } +} diff --git a/api/src/test/java/io/opencensus/metrics/export/TimeSeriesTest.java b/api/src/test/java/io/opencensus/metrics/export/TimeSeriesTest.java new file mode 100644 index 00000000..31812549 --- /dev/null +++ b/api/src/test/java/io/opencensus/metrics/export/TimeSeriesTest.java @@ -0,0 +1,117 @@ +/* + * Copyright 2018, OpenCensus Authors + * + * 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 + * + * http://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.opencensus.metrics.export; + +import static com.google.common.truth.Truth.assertThat; + +import com.google.common.testing.EqualsTester; +import io.opencensus.common.Timestamp; +import io.opencensus.metrics.LabelValue; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import org.hamcrest.CoreMatchers; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +/** Unit tests for {@link TimeSeries}. */ +@RunWith(JUnit4.class) +public class TimeSeriesTest { + + @Rule public ExpectedException thrown = ExpectedException.none(); + + private static final LabelValue LABEL_VALUE_1 = LabelValue.create("value1"); + private static final LabelValue LABEL_VALUE_2 = LabelValue.create("value2"); + private static final Value VALUE_LONG = Value.longValue(12345678); + private static final Value VALUE_DOUBLE = Value.doubleValue(-345.77); + private static final Timestamp TIMESTAMP_1 = Timestamp.fromMillis(1000); + private static final Timestamp TIMESTAMP_2 = Timestamp.fromMillis(2000); + private static final Timestamp TIMESTAMP_3 = Timestamp.fromMillis(3000); + private static final Point POINT_1 = Point.create(VALUE_DOUBLE, TIMESTAMP_2); + private static final Point POINT_2 = Point.create(VALUE_LONG, TIMESTAMP_3); + + @Test + public void testGet_TimeSeries() { + TimeSeries cumulativeTimeSeries = + TimeSeries.create( + Arrays.asList(LABEL_VALUE_1, LABEL_VALUE_2), Arrays.asList(POINT_1), TIMESTAMP_1); + assertThat(cumulativeTimeSeries.getStartTimestamp()).isEqualTo(TIMESTAMP_1); + assertThat(cumulativeTimeSeries.getLabelValues()) + .containsExactly(LABEL_VALUE_1, LABEL_VALUE_2) + .inOrder(); + assertThat(cumulativeTimeSeries.getPoints()).containsExactly(POINT_1).inOrder(); + } + + @Test + public void create_WithNullLabelValueList() { + thrown.expect(NullPointerException.class); + thrown.expectMessage(CoreMatchers.equalTo("labelValues")); + TimeSeries.create(null, Collections.emptyList(), TIMESTAMP_1); + } + + @Test + public void create_WithNullLabelValue() { + List labelValues = Arrays.asList(LABEL_VALUE_1, null); + thrown.expect(NullPointerException.class); + thrown.expectMessage(CoreMatchers.equalTo("labelValue")); + TimeSeries.create(labelValues, Collections.emptyList(), TIMESTAMP_1); + } + + @Test + public void create_WithNullPointList() { + thrown.expect(NullPointerException.class); + thrown.expectMessage(CoreMatchers.equalTo("points")); + TimeSeries.create(Collections.emptyList(), null, TIMESTAMP_1); + } + + @Test + public void create_WithNullPoint() { + List points = Arrays.asList(POINT_1, null); + thrown.expect(NullPointerException.class); + thrown.expectMessage(CoreMatchers.equalTo("point")); + TimeSeries.create(Collections.emptyList(), points, TIMESTAMP_1); + } + + @Test + public void testEquals() { + new EqualsTester() + .addEqualityGroup( + TimeSeries.create( + Arrays.asList(LABEL_VALUE_1, LABEL_VALUE_2), Arrays.asList(POINT_1), TIMESTAMP_1), + TimeSeries.create( + Arrays.asList(LABEL_VALUE_1, LABEL_VALUE_2), Arrays.asList(POINT_1), TIMESTAMP_1)) + .addEqualityGroup( + TimeSeries.create( + Arrays.asList(LABEL_VALUE_1, LABEL_VALUE_2), Arrays.asList(POINT_1), null), + TimeSeries.create( + Arrays.asList(LABEL_VALUE_1, LABEL_VALUE_2), Arrays.asList(POINT_1), null)) + .addEqualityGroup( + TimeSeries.create( + Arrays.asList(LABEL_VALUE_1, LABEL_VALUE_2), Arrays.asList(POINT_1), TIMESTAMP_2)) + .addEqualityGroup( + TimeSeries.create(Arrays.asList(LABEL_VALUE_1), Arrays.asList(POINT_1), TIMESTAMP_2)) + .addEqualityGroup( + TimeSeries.create(Arrays.asList(LABEL_VALUE_1), Arrays.asList(POINT_2), TIMESTAMP_2)) + .addEqualityGroup( + TimeSeries.create( + Arrays.asList(LABEL_VALUE_1), Arrays.asList(POINT_1, POINT_2), TIMESTAMP_2)) + .testEquals(); + } +} diff --git a/api/src/test/java/io/opencensus/metrics/export/ValueTest.java b/api/src/test/java/io/opencensus/metrics/export/ValueTest.java new file mode 100644 index 00000000..3758ed2d --- /dev/null +++ b/api/src/test/java/io/opencensus/metrics/export/ValueTest.java @@ -0,0 +1,155 @@ +/* + * Copyright 2018, OpenCensus Authors + * + * 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 + * + * http://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.opencensus.metrics.export; + +import static com.google.common.truth.Truth.assertThat; + +import com.google.common.testing.EqualsTester; +import io.opencensus.common.Function; +import io.opencensus.common.Functions; +import io.opencensus.metrics.export.Distribution.Bucket; +import io.opencensus.metrics.export.Summary.Snapshot; +import io.opencensus.metrics.export.Summary.Snapshot.ValueAtPercentile; +import io.opencensus.metrics.export.Value.ValueDistribution; +import io.opencensus.metrics.export.Value.ValueDouble; +import io.opencensus.metrics.export.Value.ValueLong; +import io.opencensus.metrics.export.Value.ValueSummary; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +/** Unit tests for {@link Value}. */ +@RunWith(JUnit4.class) +public class ValueTest { + private static final double TOLERANCE = 1e-6; + + private static final Distribution DISTRIBUTION = + Distribution.create( + 10, + 10, + 1, + Arrays.asList(-5.0, 0.0, 5.0), + Arrays.asList(Bucket.create(3), Bucket.create(1), Bucket.create(2), Bucket.create(4))); + private static final Summary SUMMARY = + Summary.create( + 10L, + 10.0, + Snapshot.create( + 10L, 87.07, Collections.singletonList(ValueAtPercentile.create(0.98, 10.2)))); + + @Test + public void createAndGet_ValueDouble() { + Value value = Value.doubleValue(-34.56); + assertThat(value).isInstanceOf(ValueDouble.class); + assertThat(((ValueDouble) value).getValue()).isWithin(TOLERANCE).of(-34.56); + } + + @Test + public void createAndGet_ValueLong() { + Value value = Value.longValue(123456789); + assertThat(value).isInstanceOf(ValueLong.class); + assertThat(((ValueLong) value).getValue()).isEqualTo(123456789); + } + + @Test + public void createAndGet_ValueDistribution() { + Value value = Value.distributionValue(DISTRIBUTION); + assertThat(value).isInstanceOf(ValueDistribution.class); + assertThat(((ValueDistribution) value).getValue()).isEqualTo(DISTRIBUTION); + } + + @Test + public void createAndGet_ValueSummary() { + Value value = Value.summaryValue(SUMMARY); + assertThat(value).isInstanceOf(ValueSummary.class); + assertThat(((ValueSummary) value).getValue()).isEqualTo(SUMMARY); + } + + @Test + public void testEquals() { + new EqualsTester() + .addEqualityGroup(Value.doubleValue(1.0), Value.doubleValue(1.0)) + .addEqualityGroup(Value.doubleValue(2.0)) + .addEqualityGroup(Value.longValue(1L)) + .addEqualityGroup(Value.longValue(2L)) + .addEqualityGroup( + Value.distributionValue( + Distribution.create( + 7, + 10, + 23.456, + Arrays.asList(-5.0, 0.0, 5.0), + Arrays.asList( + Bucket.create(3), Bucket.create(1), Bucket.create(2), Bucket.create(4))))) + .testEquals(); + } + + @Test + public void testMatch() { + List values = + Arrays.asList( + ValueDouble.create(1.0), + ValueLong.create(-1), + ValueDistribution.create(DISTRIBUTION), + ValueSummary.create(SUMMARY)); + List expected = + Arrays.asList(1.0, -1L, 10.0, 10L, 1.0, -5.0, 0.0, 5.0, 3L, 1L, 2L, 4L); + final List actual = new ArrayList(); + for (Value value : values) { + value.match( + new Function() { + @Override + public Object apply(Double arg) { + actual.add(arg); + return null; + } + }, + new Function() { + @Override + public Object apply(Long arg) { + actual.add(arg); + return null; + } + }, + new Function() { + @Override + public Object apply(Distribution arg) { + actual.add(arg.getSum()); + actual.add(arg.getCount()); + actual.add(arg.getSumOfSquaredDeviations()); + actual.addAll(arg.getBucketBoundaries()); + for (Bucket bucket : arg.getBuckets()) { + actual.add(bucket.getCount()); + } + return null; + } + }, + new Function() { + @Override + public Object apply(Summary arg) { + return null; + } + }, + Functions.throwAssertionError()); + } + assertThat(actual).containsExactlyElementsIn(expected).inOrder(); + } +} -- cgit v1.2.3