blob: d55f101cab1282fa6cea38baaa22c721ac062821 [file] [log] [blame]
/*
* 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 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 bucketOptions the bucket options used to create a histogram for the distribution.
* @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,
BucketOptions bucketOptions,
List<Bucket> 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.");
}
Utils.checkNotNull(bucketOptions, "bucketOptions");
List<Bucket> bucketsCopy =
Collections.unmodifiableList(new ArrayList<Bucket>(Utils.checkNotNull(buckets, "buckets")));
Utils.checkListElementNotNull(bucketsCopy, "bucket");
return new AutoValue_Distribution(
count, sum, sumOfSquaredDeviations, bucketOptions, 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.
*
* <p>The sum of squared deviations from the mean of the values in the population. For values x_i
* this is:
*
* <p>Sum[i=1..n]((x_i - mean)^2)
*
* <p>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 bucket options used to create a histogram for the distribution.
*
* @return the {@code BucketOptions} associated with the {@code Distribution}, or {@code null} if
* there isn't one.
* @since 0.17
*/
@Nullable
public abstract BucketOptions getBucketOptions();
/**
* Returns the aggregated histogram {@link Bucket}s.
*
* @return the aggregated histogram buckets.
* @since 0.17
*/
public abstract List<Bucket> getBuckets();
/**
* The bucket options used to create a histogram for the distribution.
*
* @since 0.17
*/
@Immutable
public abstract static class BucketOptions {
private BucketOptions() {}
/**
* Returns a {@link ExplicitOptions}.
*
* <p>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:
*
* <ul>
* <li>{@code [0, bucket_bounds[i]) for i == 0}
* <li>{@code [bucket_bounds[i-1], bucket_bounds[i]) for 0 < i < N-1}
* <li>{@code [bucket_bounds[i-1], +infinity) for i == N-1}
* </ul>
*
* <p>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.
*
* @param bucketBoundaries the bucket boundaries of a distribution (given explicitly). The
* values must be strictly increasing and should be positive values.
* @return a {@code ExplicitOptions} {@code BucketOptions}.
* @since 0.17
*/
public static BucketOptions explicitOptions(List<Double> bucketBoundaries) {
return ExplicitOptions.create(bucketBoundaries);
}
/**
* Applies the given match function to the underlying BucketOptions.
*
* @param explicitFunction the function that should be applied if the BucketOptions has type
* {@code ExplicitOptions}.
* @param defaultFunction the function that should be applied if the BucketOptions has a type
* that was added after this {@code match} method was added to the API. See {@link
* io.opencensus.common.Functions} for some common functions for handling unknown types.
* @return the result of the function applied to the underlying BucketOptions.
* @since 0.17
*/
public abstract <T> T match(
Function<? super ExplicitOptions, T> explicitFunction,
Function<? super BucketOptions, T> defaultFunction);
/** A Bucket with explicit bounds {@link BucketOptions}. */
@AutoValue
@Immutable
public abstract static class ExplicitOptions extends BucketOptions {
ExplicitOptions() {}
@Override
public final <T> T match(
Function<? super ExplicitOptions, T> explicitFunction,
Function<? super BucketOptions, T> defaultFunction) {
return explicitFunction.apply(this);
}
/**
* Creates a {@link ExplicitOptions}.
*
* @param bucketBoundaries the bucket boundaries of a distribution (given explicitly). The
* values must be strictly increasing and should be positive.
* @return a {@code ExplicitOptions}.
* @since 0.17
*/
private static ExplicitOptions create(List<Double> bucketBoundaries) {
Utils.checkNotNull(bucketBoundaries, "bucketBoundaries");
List<Double> bucketBoundariesCopy =
Collections.unmodifiableList(new ArrayList<Double>(bucketBoundaries));
checkBucketBoundsAreSorted(bucketBoundariesCopy);
return new AutoValue_Distribution_BucketOptions_ExplicitOptions(bucketBoundariesCopy);
}
private static void checkBucketBoundsAreSorted(List<Double> bucketBoundaries) {
if (bucketBoundaries.size() >= 1) {
double previous = Utils.checkNotNull(bucketBoundaries.get(0), "bucketBoundary");
Utils.checkArgument(previous > 0, "bucket boundary should be > 0");
for (int i = 1; i < bucketBoundaries.size(); i++) {
double next = Utils.checkNotNull(bucketBoundaries.get(i), "bucketBoundary");
Utils.checkArgument(previous < next, "bucket boundaries not sorted.");
previous = next;
}
}
}
/**
* Returns the bucket boundaries of this distribution.
*
* @return the bucket boundaries of this distribution.
* @since 0.17
*/
public abstract List<Double> getBucketBoundaries();
}
}
/**
* 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<String, String> 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<String, String> attachments) {
Utils.checkNotNull(attachments, "attachments");
Map<String, String> attachmentsCopy =
Collections.unmodifiableMap(new HashMap<String, String>(attachments));
for (Entry<String, String> 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);
}
}
}