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.implcore.stats; 18 19 import static com.google.common.base.Preconditions.checkArgument; 20 import static com.google.common.base.Preconditions.checkNotNull; 21 22 import com.google.common.collect.Maps; 23 import io.opencensus.common.Duration; 24 import io.opencensus.common.Timestamp; 25 import io.opencensus.stats.Aggregation; 26 import io.opencensus.stats.Measure; 27 import io.opencensus.tags.TagValue; 28 import java.util.List; 29 import java.util.Map; 30 31 /*>>> 32 import org.checkerframework.checker.nullness.qual.Nullable; 33 */ 34 35 /** The bucket with aggregated {@code MeasureValue}s used for {@code IntervalViewData}. */ 36 final class IntervalBucket { 37 38 private static final Duration ZERO = Duration.create(0, 0); 39 40 private final Timestamp start; 41 private final Duration duration; 42 private final Aggregation aggregation; 43 private final Measure measure; 44 private final Map<List</*@Nullable*/ TagValue>, MutableAggregation> tagValueAggregationMap = 45 Maps.newHashMap(); 46 IntervalBucket(Timestamp start, Duration duration, Aggregation aggregation, Measure measure)47 IntervalBucket(Timestamp start, Duration duration, Aggregation aggregation, Measure measure) { 48 this.start = checkNotNull(start, "Start"); 49 this.duration = checkNotNull(duration, "Duration"); 50 checkArgument(duration.compareTo(ZERO) > 0, "Duration must be positive"); 51 this.aggregation = checkNotNull(aggregation, "Aggregation"); 52 this.measure = checkNotNull(measure, "measure"); 53 } 54 getTagValueAggregationMap()55 Map<List</*@Nullable*/ TagValue>, MutableAggregation> getTagValueAggregationMap() { 56 return tagValueAggregationMap; 57 } 58 getStart()59 Timestamp getStart() { 60 return start; 61 } 62 63 // Puts a new value into the internal MutableAggregations, based on the TagValues. record( List< TagValue> tagValues, double value, Map<String, String> attachments, Timestamp timestamp)64 void record( 65 List</*@Nullable*/ TagValue> tagValues, 66 double value, 67 Map<String, String> attachments, 68 Timestamp timestamp) { 69 if (!tagValueAggregationMap.containsKey(tagValues)) { 70 tagValueAggregationMap.put( 71 tagValues, RecordUtils.createMutableAggregation(aggregation, measure)); 72 } 73 tagValueAggregationMap.get(tagValues).add(value, attachments, timestamp); 74 } 75 76 /* 77 * Returns how much fraction of duration has passed in this IntervalBucket. For example, if this 78 * bucket starts at 10s and has a duration of 20s, and now is 15s, then getFraction() should 79 * return (15 - 10) / 20 = 0.25. 80 * 81 * This IntervalBucket must be current, i.e. the current timestamp must be within 82 * [this.start, this.start + this.duration). 83 */ getFraction(Timestamp now)84 double getFraction(Timestamp now) { 85 Duration elapsedTime = now.subtractTimestamp(start); 86 checkArgument( 87 elapsedTime.compareTo(ZERO) >= 0 && elapsedTime.compareTo(duration) < 0, 88 "This bucket must be current."); 89 return ((double) elapsedTime.toMillis()) / duration.toMillis(); 90 } 91 92 void clearStats() { 93 tagValueAggregationMap.clear(); 94 } 95 } 96