Home | History | Annotate | Download | only in export
      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.common.Timestamp;
     23 import io.opencensus.internal.Utils;
     24 import java.util.ArrayList;
     25 import java.util.Collections;
     26 import java.util.HashMap;
     27 import java.util.List;
     28 import java.util.Map;
     29 import java.util.Map.Entry;
     30 import javax.annotation.Nullable;
     31 import javax.annotation.concurrent.Immutable;
     32 
     33 /**
     34  * {@link Distribution} contains summary statistics for a population of values. It optionally
     35  * contains a histogram representing the distribution of those values across a set of buckets.
     36  *
     37  * @since 0.17
     38  */
     39 @ExperimentalApi
     40 @AutoValue
     41 @Immutable
     42 public abstract class Distribution {
     43 
     44   Distribution() {}
     45 
     46   /**
     47    * Creates a {@link Distribution}.
     48    *
     49    * @param count the count of the population values.
     50    * @param sum the sum of the population values.
     51    * @param sumOfSquaredDeviations the sum of squared deviations of the population values.
     52    * @param bucketOptions the bucket options used to create a histogram for the distribution.
     53    * @param buckets {@link Bucket}s of a histogram.
     54    * @return a {@code Distribution}.
     55    * @since 0.17
     56    */
     57   public static Distribution create(
     58       long count,
     59       double sum,
     60       double sumOfSquaredDeviations,
     61       BucketOptions bucketOptions,
     62       List<Bucket> buckets) {
     63     Utils.checkArgument(count >= 0, "count should be non-negative.");
     64     Utils.checkArgument(
     65         sumOfSquaredDeviations >= 0, "sum of squared deviations should be non-negative.");
     66     if (count == 0) {
     67       Utils.checkArgument(sum == 0, "sum should be 0 if count is 0.");
     68       Utils.checkArgument(
     69           sumOfSquaredDeviations == 0, "sum of squared deviations should be 0 if count is 0.");
     70     }
     71     Utils.checkNotNull(bucketOptions, "bucketOptions");
     72     List<Bucket> bucketsCopy =
     73         Collections.unmodifiableList(new ArrayList<Bucket>(Utils.checkNotNull(buckets, "buckets")));
     74     Utils.checkListElementNotNull(bucketsCopy, "bucket");
     75     return new AutoValue_Distribution(
     76         count, sum, sumOfSquaredDeviations, bucketOptions, bucketsCopy);
     77   }
     78 
     79   /**
     80    * Returns the aggregated count.
     81    *
     82    * @return the aggregated count.
     83    * @since 0.17
     84    */
     85   public abstract long getCount();
     86 
     87   /**
     88    * Returns the aggregated sum.
     89    *
     90    * @return the aggregated sum.
     91    * @since 0.17
     92    */
     93   public abstract double getSum();
     94 
     95   /**
     96    * Returns the aggregated sum of squared deviations.
     97    *
     98    * <p>The sum of squared deviations from the mean of the values in the population. For values x_i
     99    * this is:
    100    *
    101    * <p>Sum[i=1..n]((x_i - mean)^2)
    102    *
    103    * <p>If count is zero then this field must be zero.
    104    *
    105    * @return the aggregated sum of squared deviations.
    106    * @since 0.17
    107    */
    108   public abstract double getSumOfSquaredDeviations();
    109 
    110   /**
    111    * Returns bucket options used to create a histogram for the distribution.
    112    *
    113    * @return the {@code BucketOptions} associated with the {@code Distribution}, or {@code null} if
    114    *     there isn't one.
    115    * @since 0.17
    116    */
    117   @Nullable
    118   public abstract BucketOptions getBucketOptions();
    119 
    120   /**
    121    * Returns the aggregated histogram {@link Bucket}s.
    122    *
    123    * @return the aggregated histogram buckets.
    124    * @since 0.17
    125    */
    126   public abstract List<Bucket> getBuckets();
    127 
    128   /**
    129    * The bucket options used to create a histogram for the distribution.
    130    *
    131    * @since 0.17
    132    */
    133   @Immutable
    134   public abstract static class BucketOptions {
    135 
    136     private BucketOptions() {}
    137 
    138     /**
    139      * Returns a {@link ExplicitOptions}.
    140      *
    141      * <p>The bucket boundaries for that histogram are described by bucket_bounds. This defines
    142      * size(bucket_bounds) + 1 (= N) buckets. The boundaries for bucket index i are:
    143      *
    144      * <ul>
    145      *   <li>{@code [0, bucket_bounds[i]) for i == 0}
    146      *   <li>{@code [bucket_bounds[i-1], bucket_bounds[i]) for 0 < i < N-1}
    147      *   <li>{@code [bucket_bounds[i-1], +infinity) for i == N-1}
    148      * </ul>
    149      *
    150      * <p>If bucket_bounds has no elements (zero size), then there is no histogram associated with
    151      * the Distribution. If bucket_bounds has only one element, there are no finite buckets, and
    152      * that single element is the common boundary of the overflow and underflow buckets. The values
    153      * must be monotonically increasing.
    154      *
    155      * @param bucketBoundaries the bucket boundaries of a distribution (given explicitly). The
    156      *     values must be strictly increasing and should be positive values.
    157      * @return a {@code ExplicitOptions} {@code BucketOptions}.
    158      * @since 0.17
    159      */
    160     public static BucketOptions explicitOptions(List<Double> bucketBoundaries) {
    161       return ExplicitOptions.create(bucketBoundaries);
    162     }
    163 
    164     /**
    165      * Applies the given match function to the underlying BucketOptions.
    166      *
    167      * @param explicitFunction the function that should be applied if the BucketOptions has type
    168      *     {@code ExplicitOptions}.
    169      * @param defaultFunction the function that should be applied if the BucketOptions has a type
    170      *     that was added after this {@code match} method was added to the API. See {@link
    171      *     io.opencensus.common.Functions} for some common functions for handling unknown types.
    172      * @return the result of the function applied to the underlying BucketOptions.
    173      * @since 0.17
    174      */
    175     public abstract <T> T match(
    176         Function<? super ExplicitOptions, T> explicitFunction,
    177         Function<? super BucketOptions, T> defaultFunction);
    178 
    179     /** A Bucket with explicit bounds {@link BucketOptions}. */
    180     @AutoValue
    181     @Immutable
    182     public abstract static class ExplicitOptions extends BucketOptions {
    183 
    184       ExplicitOptions() {}
    185 
    186       @Override
    187       public final <T> T match(
    188           Function<? super ExplicitOptions, T> explicitFunction,
    189           Function<? super BucketOptions, T> defaultFunction) {
    190         return explicitFunction.apply(this);
    191       }
    192 
    193       /**
    194        * Creates a {@link ExplicitOptions}.
    195        *
    196        * @param bucketBoundaries the bucket boundaries of a distribution (given explicitly). The
    197        *     values must be strictly increasing and should be positive.
    198        * @return a {@code ExplicitOptions}.
    199        * @since 0.17
    200        */
    201       private static ExplicitOptions create(List<Double> bucketBoundaries) {
    202         Utils.checkNotNull(bucketBoundaries, "bucketBoundaries");
    203         List<Double> bucketBoundariesCopy =
    204             Collections.unmodifiableList(new ArrayList<Double>(bucketBoundaries));
    205         checkBucketBoundsAreSorted(bucketBoundariesCopy);
    206         return new AutoValue_Distribution_BucketOptions_ExplicitOptions(bucketBoundariesCopy);
    207       }
    208 
    209       private static void checkBucketBoundsAreSorted(List<Double> bucketBoundaries) {
    210         if (bucketBoundaries.size() >= 1) {
    211           double previous = Utils.checkNotNull(bucketBoundaries.get(0), "bucketBoundary");
    212           Utils.checkArgument(previous > 0, "bucket boundary should be > 0");
    213           for (int i = 1; i < bucketBoundaries.size(); i++) {
    214             double next = Utils.checkNotNull(bucketBoundaries.get(i), "bucketBoundary");
    215             Utils.checkArgument(previous < next, "bucket boundaries not sorted.");
    216             previous = next;
    217           }
    218         }
    219       }
    220 
    221       /**
    222        * Returns the bucket boundaries of this distribution.
    223        *
    224        * @return the bucket boundaries of this distribution.
    225        * @since 0.17
    226        */
    227       public abstract List<Double> getBucketBoundaries();
    228     }
    229   }
    230 
    231   /**
    232    * The histogram bucket of the population values.
    233    *
    234    * @since 0.17
    235    */
    236   @AutoValue
    237   @Immutable
    238   public abstract static class Bucket {
    239 
    240     Bucket() {}
    241 
    242     /**
    243      * Creates a {@link Bucket}.
    244      *
    245      * @param count the number of values in each bucket of the histogram.
    246      * @return a {@code Bucket}.
    247      * @since 0.17
    248      */
    249     public static Bucket create(long count) {
    250       Utils.checkArgument(count >= 0, "bucket count should be non-negative.");
    251       return new AutoValue_Distribution_Bucket(count, null);
    252     }
    253 
    254     /**
    255      * Creates a {@link Bucket} with an {@link Exemplar}.
    256      *
    257      * @param count the number of values in each bucket of the histogram.
    258      * @param exemplar the {@code Exemplar} of this {@code Bucket}.
    259      * @return a {@code Bucket}.
    260      * @since 0.17
    261      */
    262     public static Bucket create(long count, Exemplar exemplar) {
    263       Utils.checkArgument(count >= 0, "bucket count should be non-negative.");
    264       Utils.checkNotNull(exemplar, "exemplar");
    265       return new AutoValue_Distribution_Bucket(count, exemplar);
    266     }
    267 
    268     /**
    269      * Returns the number of values in each bucket of the histogram.
    270      *
    271      * @return the number of values in each bucket of the histogram.
    272      * @since 0.17
    273      */
    274     public abstract long getCount();
    275 
    276     /**
    277      * Returns the {@link Exemplar} associated with the {@link Bucket}, or {@code null} if there
    278      * isn't one.
    279      *
    280      * @return the {@code Exemplar} associated with the {@code Bucket}, or {@code null} if there
    281      *     isn't one.
    282      * @since 0.17
    283      */
    284     @Nullable
    285     public abstract Exemplar getExemplar();
    286   }
    287 
    288   /**
    289    * An example point that may be used to annotate aggregated distribution values, associated with a
    290    * histogram bucket.
    291    *
    292    * @since 0.17
    293    */
    294   @Immutable
    295   @AutoValue
    296   public abstract static class Exemplar {
    297 
    298     Exemplar() {}
    299 
    300     /**
    301      * Returns value of the {@link Exemplar} point.
    302      *
    303      * @return value of the {@code Exemplar} point.
    304      * @since 0.17
    305      */
    306     public abstract double getValue();
    307 
    308     /**
    309      * Returns the time that this {@link Exemplar}'s value was recorded.
    310      *
    311      * @return the time that this {@code Exemplar}'s value was recorded.
    312      * @since 0.17
    313      */
    314     public abstract Timestamp getTimestamp();
    315 
    316     /**
    317      * Returns the contextual information about the example value, represented as a string map.
    318      *
    319      * @return the contextual information about the example value.
    320      * @since 0.17
    321      */
    322     public abstract Map<String, String> getAttachments();
    323 
    324     /**
    325      * Creates an {@link Exemplar}.
    326      *
    327      * @param value value of the {@link Exemplar} point.
    328      * @param timestamp the time that this {@code Exemplar}'s value was recorded.
    329      * @param attachments the contextual information about the example value.
    330      * @return an {@code Exemplar}.
    331      * @since 0.17
    332      */
    333     public static Exemplar create(
    334         double value, Timestamp timestamp, Map<String, String> attachments) {
    335       Utils.checkNotNull(attachments, "attachments");
    336       Map<String, String> attachmentsCopy =
    337           Collections.unmodifiableMap(new HashMap<String, String>(attachments));
    338       for (Entry<String, String> entry : attachmentsCopy.entrySet()) {
    339         Utils.checkNotNull(entry.getKey(), "key of attachments");
    340         Utils.checkNotNull(entry.getValue(), "value of attachments");
    341       }
    342       return new AutoValue_Distribution_Exemplar(value, timestamp, attachmentsCopy);
    343     }
    344   }
    345 }
    346