• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2018, OpenCensus Authors
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package io.opencensus.metrics.export;
18 
19 import com.google.auto.value.AutoValue;
20 import io.opencensus.common.ExperimentalApi;
21 import io.opencensus.common.Function;
22 import io.opencensus.internal.Utils;
23 import io.opencensus.metrics.data.Exemplar;
24 import java.util.ArrayList;
25 import java.util.Collections;
26 import java.util.List;
27 import javax.annotation.Nullable;
28 import javax.annotation.concurrent.Immutable;
29 
30 /**
31  * {@link Distribution} contains summary statistics for a population of values. It optionally
32  * contains a histogram representing the distribution of those values across a set of buckets.
33  *
34  * @since 0.17
35  */
36 @ExperimentalApi
37 @AutoValue
38 @Immutable
39 public abstract class Distribution {
40 
Distribution()41   Distribution() {}
42 
43   /**
44    * Creates a {@link Distribution}.
45    *
46    * @param count the count of the population values.
47    * @param sum the sum of the population values.
48    * @param sumOfSquaredDeviations the sum of squared deviations of the population values.
49    * @param bucketOptions the bucket options used to create a histogram for the distribution.
50    * @param buckets {@link Bucket}s of a histogram.
51    * @return a {@code Distribution}.
52    * @since 0.17
53    */
create( long count, double sum, double sumOfSquaredDeviations, BucketOptions bucketOptions, List<Bucket> buckets)54   public static Distribution create(
55       long count,
56       double sum,
57       double sumOfSquaredDeviations,
58       BucketOptions bucketOptions,
59       List<Bucket> buckets) {
60     Utils.checkArgument(count >= 0, "count should be non-negative.");
61     Utils.checkArgument(
62         sumOfSquaredDeviations >= 0, "sum of squared deviations should be non-negative.");
63     if (count == 0) {
64       Utils.checkArgument(sum == 0, "sum should be 0 if count is 0.");
65       Utils.checkArgument(
66           sumOfSquaredDeviations == 0, "sum of squared deviations should be 0 if count is 0.");
67     }
68     Utils.checkNotNull(bucketOptions, "bucketOptions");
69     List<Bucket> bucketsCopy =
70         Collections.unmodifiableList(new ArrayList<Bucket>(Utils.checkNotNull(buckets, "buckets")));
71     Utils.checkListElementNotNull(bucketsCopy, "bucket");
72     return new AutoValue_Distribution(
73         count, sum, sumOfSquaredDeviations, bucketOptions, bucketsCopy);
74   }
75 
76   /**
77    * Returns the aggregated count.
78    *
79    * @return the aggregated count.
80    * @since 0.17
81    */
getCount()82   public abstract long getCount();
83 
84   /**
85    * Returns the aggregated sum.
86    *
87    * @return the aggregated sum.
88    * @since 0.17
89    */
getSum()90   public abstract double getSum();
91 
92   /**
93    * Returns the aggregated sum of squared deviations.
94    *
95    * <p>The sum of squared deviations from the mean of the values in the population. For values x_i
96    * this is:
97    *
98    * <p>Sum[i=1..n]((x_i - mean)^2)
99    *
100    * <p>If count is zero then this field must be zero.
101    *
102    * @return the aggregated sum of squared deviations.
103    * @since 0.17
104    */
getSumOfSquaredDeviations()105   public abstract double getSumOfSquaredDeviations();
106 
107   /**
108    * Returns bucket options used to create a histogram for the distribution.
109    *
110    * @return the {@code BucketOptions} associated with the {@code Distribution}, or {@code null} if
111    *     there isn't one.
112    * @since 0.17
113    */
114   @Nullable
getBucketOptions()115   public abstract BucketOptions getBucketOptions();
116 
117   /**
118    * Returns the aggregated histogram {@link Bucket}s.
119    *
120    * @return the aggregated histogram buckets.
121    * @since 0.17
122    */
getBuckets()123   public abstract List<Bucket> getBuckets();
124 
125   /**
126    * The bucket options used to create a histogram for the distribution.
127    *
128    * @since 0.17
129    */
130   @Immutable
131   public abstract static class BucketOptions {
132 
BucketOptions()133     private BucketOptions() {}
134 
135     /**
136      * Returns a {@link ExplicitOptions}.
137      *
138      * <p>The bucket boundaries for that histogram are described by bucket_bounds. This defines
139      * size(bucket_bounds) + 1 (= N) buckets. The boundaries for bucket index i are:
140      *
141      * <ul>
142      *   <li>{@code [0, bucket_bounds[i]) for i == 0}
143      *   <li>{@code [bucket_bounds[i-1], bucket_bounds[i]) for 0 < i < N-1}
144      *   <li>{@code [bucket_bounds[i-1], +infinity) for i == N-1}
145      * </ul>
146      *
147      * <p>If bucket_bounds has no elements (zero size), then there is no histogram associated with
148      * the Distribution. If bucket_bounds has only one element, there are no finite buckets, and
149      * that single element is the common boundary of the overflow and underflow buckets. The values
150      * must be monotonically increasing.
151      *
152      * @param bucketBoundaries the bucket boundaries of a distribution (given explicitly). The
153      *     values must be strictly increasing and should be positive values.
154      * @return a {@code ExplicitOptions} {@code BucketOptions}.
155      * @since 0.17
156      */
explicitOptions(List<Double> bucketBoundaries)157     public static BucketOptions explicitOptions(List<Double> bucketBoundaries) {
158       return ExplicitOptions.create(bucketBoundaries);
159     }
160 
161     /**
162      * Applies the given match function to the underlying BucketOptions.
163      *
164      * @param explicitFunction the function that should be applied if the BucketOptions has type
165      *     {@code ExplicitOptions}.
166      * @param defaultFunction the function that should be applied if the BucketOptions has a type
167      *     that was added after this {@code match} method was added to the API. See {@link
168      *     io.opencensus.common.Functions} for some common functions for handling unknown types.
169      * @return the result of the function applied to the underlying BucketOptions.
170      * @since 0.17
171      */
match( Function<? super ExplicitOptions, T> explicitFunction, Function<? super BucketOptions, T> defaultFunction)172     public abstract <T> T match(
173         Function<? super ExplicitOptions, T> explicitFunction,
174         Function<? super BucketOptions, T> defaultFunction);
175 
176     /** A Bucket with explicit bounds {@link BucketOptions}. */
177     @AutoValue
178     @Immutable
179     public abstract static class ExplicitOptions extends BucketOptions {
180 
ExplicitOptions()181       ExplicitOptions() {}
182 
183       @Override
match( Function<? super ExplicitOptions, T> explicitFunction, Function<? super BucketOptions, T> defaultFunction)184       public final <T> T match(
185           Function<? super ExplicitOptions, T> explicitFunction,
186           Function<? super BucketOptions, T> defaultFunction) {
187         return explicitFunction.apply(this);
188       }
189 
190       /**
191        * Creates a {@link ExplicitOptions}.
192        *
193        * @param bucketBoundaries the bucket boundaries of a distribution (given explicitly). The
194        *     values must be strictly increasing and should be positive.
195        * @return a {@code ExplicitOptions}.
196        * @since 0.17
197        */
create(List<Double> bucketBoundaries)198       private static ExplicitOptions create(List<Double> bucketBoundaries) {
199         Utils.checkNotNull(bucketBoundaries, "bucketBoundaries");
200         List<Double> bucketBoundariesCopy =
201             Collections.unmodifiableList(new ArrayList<Double>(bucketBoundaries));
202         checkBucketBoundsAreSorted(bucketBoundariesCopy);
203         return new AutoValue_Distribution_BucketOptions_ExplicitOptions(bucketBoundariesCopy);
204       }
205 
checkBucketBoundsAreSorted(List<Double> bucketBoundaries)206       private static void checkBucketBoundsAreSorted(List<Double> bucketBoundaries) {
207         if (bucketBoundaries.size() >= 1) {
208           double previous = Utils.checkNotNull(bucketBoundaries.get(0), "bucketBoundary");
209           Utils.checkArgument(previous > 0, "bucket boundary should be > 0");
210           for (int i = 1; i < bucketBoundaries.size(); i++) {
211             double next = Utils.checkNotNull(bucketBoundaries.get(i), "bucketBoundary");
212             Utils.checkArgument(previous < next, "bucket boundaries not sorted.");
213             previous = next;
214           }
215         }
216       }
217 
218       /**
219        * Returns the bucket boundaries of this distribution.
220        *
221        * @return the bucket boundaries of this distribution.
222        * @since 0.17
223        */
224       public abstract List<Double> getBucketBoundaries();
225     }
226   }
227 
228   /**
229    * The histogram bucket of the population values.
230    *
231    * @since 0.17
232    */
233   @AutoValue
234   @Immutable
235   public abstract static class Bucket {
236 
237     Bucket() {}
238 
239     /**
240      * Creates a {@link Bucket}.
241      *
242      * @param count the number of values in each bucket of the histogram.
243      * @return a {@code Bucket}.
244      * @since 0.17
245      */
246     public static Bucket create(long count) {
247       Utils.checkArgument(count >= 0, "bucket count should be non-negative.");
248       return new AutoValue_Distribution_Bucket(count, null);
249     }
250 
251     /**
252      * Creates a {@link Bucket} with an {@link Exemplar}.
253      *
254      * @param count the number of values in each bucket of the histogram.
255      * @param exemplar the {@code Exemplar} of this {@code Bucket}.
256      * @return a {@code Bucket}.
257      * @since 0.17
258      */
create(long count, Exemplar exemplar)259     public static Bucket create(long count, Exemplar exemplar) {
260       Utils.checkArgument(count >= 0, "bucket count should be non-negative.");
261       Utils.checkNotNull(exemplar, "exemplar");
262       return new AutoValue_Distribution_Bucket(count, exemplar);
263     }
264 
265     /**
266      * Returns the number of values in each bucket of the histogram.
267      *
268      * @return the number of values in each bucket of the histogram.
269      * @since 0.17
270      */
271     public abstract long getCount();
272 
273     /**
274      * Returns the {@link Exemplar} associated with the {@link Bucket}, or {@code null} if there
275      * isn't one.
276      *
277      * @return the {@code Exemplar} associated with the {@code Bucket}, or {@code null} if there
278      *     isn't one.
279      * @since 0.17
280      */
281     @Nullable
282     public abstract Exemplar getExemplar();
283   }
284 }
285