1 /* 2 * Copyright 2017, 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.stats; 18 19 import com.google.auto.value.AutoValue; 20 import io.opencensus.internal.Utils; 21 import java.util.ArrayList; 22 import java.util.Collections; 23 import java.util.List; 24 import java.util.logging.Level; 25 import java.util.logging.Logger; 26 import javax.annotation.concurrent.Immutable; 27 28 /** 29 * The bucket boundaries for a histogram. 30 * 31 * @since 0.8 32 */ 33 @Immutable 34 @AutoValue 35 public abstract class BucketBoundaries { 36 37 private static final Logger logger = Logger.getLogger(BucketBoundaries.class.getName()); 38 39 /** 40 * Returns a {@code BucketBoundaries} with the given buckets. 41 * 42 * @param bucketBoundaries the boundaries for the buckets in the underlying histogram. 43 * @return a new {@code BucketBoundaries} with the specified boundaries. 44 * @throws NullPointerException if {@code bucketBoundaries} is null. 45 * @throws IllegalArgumentException if {@code bucketBoundaries} is not sorted. 46 * @since 0.8 47 */ create(List<Double> bucketBoundaries)48 public static final BucketBoundaries create(List<Double> bucketBoundaries) { 49 Utils.checkNotNull(bucketBoundaries, "bucketBoundaries"); 50 List<Double> bucketBoundariesCopy = new ArrayList<Double>(bucketBoundaries); // Deep copy. 51 // Check if sorted. 52 if (bucketBoundariesCopy.size() > 1) { 53 double previous = bucketBoundariesCopy.get(0); 54 for (int i = 1; i < bucketBoundariesCopy.size(); i++) { 55 double next = bucketBoundariesCopy.get(i); 56 Utils.checkArgument(previous < next, "Bucket boundaries not sorted."); 57 previous = next; 58 } 59 } 60 return new AutoValue_BucketBoundaries( 61 Collections.unmodifiableList(dropNegativeBucketBounds(bucketBoundariesCopy))); 62 } 63 64 private static List<Double> dropNegativeBucketBounds(List<Double> bucketBoundaries) { 65 // Negative values (BucketBounds) are currently not supported by any of the backends 66 // that OC supports. 67 int negativeBucketBounds = 0; 68 int zeroBucketBounds = 0; 69 for (Double value : bucketBoundaries) { 70 if (value <= 0) { 71 if (value == 0) { 72 zeroBucketBounds++; 73 } else { 74 negativeBucketBounds++; 75 } 76 } else { 77 break; 78 } 79 } 80 81 if (negativeBucketBounds > 0) { 82 logger.log( 83 Level.WARNING, 84 "Dropping " 85 + negativeBucketBounds 86 + " negative bucket boundaries, the values must be strictly > 0."); 87 } 88 return bucketBoundaries.subList( 89 negativeBucketBounds + zeroBucketBounds, bucketBoundaries.size()); 90 } 91 92 /** 93 * Returns a list of histogram bucket boundaries. 94 * 95 * @return a list of histogram bucket boundaries. 96 * @since 0.8 97 */ 98 public abstract List<Double> getBoundaries(); 99 } 100