1 /* 2 * Copyright 2016-17, 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.common.Duration; 21 import io.opencensus.common.Function; 22 import io.opencensus.common.Functions; 23 import io.opencensus.common.Timestamp; 24 import io.opencensus.stats.Aggregation.Count; 25 import io.opencensus.stats.Aggregation.Distribution; 26 import io.opencensus.stats.Aggregation.LastValue; 27 import io.opencensus.stats.Aggregation.Sum; 28 import io.opencensus.stats.AggregationData.CountData; 29 import io.opencensus.stats.AggregationData.DistributionData; 30 import io.opencensus.stats.AggregationData.LastValueDataDouble; 31 import io.opencensus.stats.AggregationData.LastValueDataLong; 32 import io.opencensus.stats.AggregationData.SumDataDouble; 33 import io.opencensus.stats.AggregationData.SumDataLong; 34 import io.opencensus.stats.Measure.MeasureDouble; 35 import io.opencensus.stats.Measure.MeasureLong; 36 import io.opencensus.tags.TagValue; 37 import java.util.ArrayList; 38 import java.util.Collections; 39 import java.util.HashMap; 40 import java.util.List; 41 import java.util.Map; 42 import java.util.Map.Entry; 43 import javax.annotation.concurrent.Immutable; 44 45 /*>>> 46 import org.checkerframework.checker.nullness.qual.Nullable; 47 */ 48 49 /** 50 * The aggregated data for a particular {@link View}. 51 * 52 * @since 0.8 53 */ 54 @Immutable 55 @AutoValue 56 @AutoValue.CopyAnnotations 57 @SuppressWarnings("deprecation") 58 public abstract class ViewData { 59 60 // Prevents this class from being subclassed anywhere else. ViewData()61 ViewData() {} 62 63 /** 64 * The {@link View} associated with this {@link ViewData}. 65 * 66 * @since 0.8 67 */ getView()68 public abstract View getView(); 69 70 /** 71 * The {@link AggregationData} grouped by combination of tag values, associated with this {@link 72 * ViewData}. 73 * 74 * @since 0.8 75 */ getAggregationMap()76 public abstract Map<List</*@Nullable*/ TagValue>, AggregationData> getAggregationMap(); 77 78 /** 79 * Returns the {@link AggregationWindowData} associated with this {@link ViewData}. 80 * 81 * <p>{@link AggregationWindowData} is deprecated since 0.13, please avoid using this method. Use 82 * {@link #getStart()} and {@link #getEnd()} instead. 83 * 84 * @return the {@code AggregationWindowData}. 85 * @since 0.8 86 * @deprecated in favor of {@link #getStart()} and {@link #getEnd()}. 87 */ 88 @Deprecated getWindowData()89 public abstract AggregationWindowData getWindowData(); 90 91 /** 92 * Returns the start {@code Timestamp} for a {@link ViewData}. 93 * 94 * @return the start {@code Timestamp}. 95 * @since 0.13 96 */ getStart()97 public abstract Timestamp getStart(); 98 99 /** 100 * Returns the end {@code Timestamp} for a {@link ViewData}. 101 * 102 * @return the end {@code Timestamp}. 103 * @since 0.13 104 */ getEnd()105 public abstract Timestamp getEnd(); 106 107 /** 108 * Constructs a new {@link ViewData}. 109 * 110 * @param view the {@link View} associated with this {@link ViewData}. 111 * @param map the mapping from {@link TagValue} list to {@link AggregationData}. 112 * @param windowData the {@link AggregationWindowData}. 113 * @return a {@code ViewData}. 114 * @throws IllegalArgumentException if the types of {@code Aggregation} and {@code 115 * AggregationData} don't match, or the types of {@code Window} and {@code WindowData} don't 116 * match. 117 * @since 0.8 118 * @deprecated in favor of {@link #create(View, Map, Timestamp, Timestamp)}. 119 */ 120 @Deprecated create( final View view, Map<? extends List< TagValue>, ? extends AggregationData> map, final AggregationWindowData windowData)121 public static ViewData create( 122 final View view, 123 Map<? extends List</*@Nullable*/ TagValue>, ? extends AggregationData> map, 124 final AggregationWindowData windowData) { 125 checkWindow(view.getWindow(), windowData); 126 final Map<List</*@Nullable*/ TagValue>, AggregationData> deepCopy = 127 new HashMap<List</*@Nullable*/ TagValue>, AggregationData>(); 128 for (Entry<? extends List</*@Nullable*/ TagValue>, ? extends AggregationData> entry : 129 map.entrySet()) { 130 checkAggregation(view.getAggregation(), entry.getValue(), view.getMeasure()); 131 deepCopy.put( 132 Collections.unmodifiableList(new ArrayList</*@Nullable*/ TagValue>(entry.getKey())), 133 entry.getValue()); 134 } 135 return windowData.match( 136 new Function<ViewData.AggregationWindowData.CumulativeData, ViewData>() { 137 @Override 138 public ViewData apply(ViewData.AggregationWindowData.CumulativeData arg) { 139 return createInternal( 140 view, Collections.unmodifiableMap(deepCopy), arg, arg.getStart(), arg.getEnd()); 141 } 142 }, 143 new Function<ViewData.AggregationWindowData.IntervalData, ViewData>() { 144 @Override 145 public ViewData apply(ViewData.AggregationWindowData.IntervalData arg) { 146 Duration duration = ((View.AggregationWindow.Interval) view.getWindow()).getDuration(); 147 return createInternal( 148 view, 149 Collections.unmodifiableMap(deepCopy), 150 arg, 151 arg.getEnd() 152 .addDuration(Duration.create(-duration.getSeconds(), -duration.getNanos())), 153 arg.getEnd()); 154 } 155 }, 156 Functions.<ViewData>throwAssertionError()); 157 } 158 159 /** 160 * Constructs a new {@link ViewData}. 161 * 162 * @param view the {@link View} associated with this {@link ViewData}. 163 * @param map the mapping from {@link TagValue} list to {@link AggregationData}. 164 * @param start the start {@link Timestamp} for this {@link ViewData}. 165 * @param end the end {@link Timestamp} for this {@link ViewData}. 166 * @return a {@code ViewData}. 167 * @throws IllegalArgumentException if the types of {@code Aggregation} and {@code 168 * AggregationData} don't match. 169 * @since 0.13 170 */ 171 public static ViewData create( 172 View view, 173 Map<? extends List</*@Nullable*/ TagValue>, ? extends AggregationData> map, 174 Timestamp start, 175 Timestamp end) { 176 Map<List</*@Nullable*/ TagValue>, AggregationData> deepCopy = 177 new HashMap<List</*@Nullable*/ TagValue>, AggregationData>(); 178 for (Entry<? extends List</*@Nullable*/ TagValue>, ? extends AggregationData> entry : 179 map.entrySet()) { 180 checkAggregation(view.getAggregation(), entry.getValue(), view.getMeasure()); 181 deepCopy.put( 182 Collections.unmodifiableList(new ArrayList</*@Nullable*/ TagValue>(entry.getKey())), 183 entry.getValue()); 184 } 185 return createInternal( 186 view, 187 Collections.unmodifiableMap(deepCopy), 188 AggregationWindowData.CumulativeData.create(start, end), 189 start, 190 end); 191 } 192 193 // Suppresses a nullness warning about calls to the AutoValue_ViewData constructor. The generated 194 // constructor does not have the @Nullable annotation on TagValue. 195 private static ViewData createInternal( 196 View view, 197 Map<List</*@Nullable*/ TagValue>, AggregationData> aggregationMap, 198 AggregationWindowData window, 199 Timestamp start, 200 Timestamp end) { 201 @SuppressWarnings("nullness") 202 Map<List<TagValue>, AggregationData> map = aggregationMap; 203 return new AutoValue_ViewData(view, map, window, start, end); 204 } 205 206 private static void checkWindow( 207 View.AggregationWindow window, final AggregationWindowData windowData) { 208 window.match( 209 new Function<View.AggregationWindow.Cumulative, Void>() { 210 @Override 211 public Void apply(View.AggregationWindow.Cumulative arg) { 212 throwIfWindowMismatch( 213 windowData instanceof AggregationWindowData.CumulativeData, arg, windowData); 214 return null; 215 } 216 }, 217 new Function<View.AggregationWindow.Interval, Void>() { 218 @Override 219 public Void apply(View.AggregationWindow.Interval arg) { 220 throwIfWindowMismatch( 221 windowData instanceof AggregationWindowData.IntervalData, arg, windowData); 222 return null; 223 } 224 }, 225 Functions.</*@Nullable*/ Void>throwAssertionError()); 226 } 227 228 private static void throwIfWindowMismatch( 229 boolean isValid, View.AggregationWindow window, AggregationWindowData windowData) { 230 if (!isValid) { 231 throw new IllegalArgumentException(createErrorMessageForWindow(window, windowData)); 232 } 233 } 234 235 private static String createErrorMessageForWindow( 236 View.AggregationWindow window, AggregationWindowData windowData) { 237 return "AggregationWindow and AggregationWindowData types mismatch. " 238 + "AggregationWindow: " 239 + window.getClass().getSimpleName() 240 + " AggregationWindowData: " 241 + windowData.getClass().getSimpleName(); 242 } 243 244 private static void checkAggregation( 245 final Aggregation aggregation, final AggregationData aggregationData, final Measure measure) { 246 aggregation.match( 247 new Function<Sum, Void>() { 248 @Override 249 public Void apply(Sum arg) { 250 measure.match( 251 new Function<MeasureDouble, Void>() { 252 @Override 253 public Void apply(MeasureDouble arg) { 254 throwIfAggregationMismatch( 255 aggregationData instanceof SumDataDouble, aggregation, aggregationData); 256 return null; 257 } 258 }, 259 new Function<MeasureLong, Void>() { 260 @Override 261 public Void apply(MeasureLong arg) { 262 throwIfAggregationMismatch( 263 aggregationData instanceof SumDataLong, aggregation, aggregationData); 264 return null; 265 } 266 }, 267 Functions.</*@Nullable*/ Void>throwAssertionError()); 268 return null; 269 } 270 }, 271 new Function<Count, Void>() { 272 @Override 273 public Void apply(Count arg) { 274 throwIfAggregationMismatch( 275 aggregationData instanceof CountData, aggregation, aggregationData); 276 return null; 277 } 278 }, 279 new Function<Distribution, Void>() { 280 @Override 281 public Void apply(Distribution arg) { 282 throwIfAggregationMismatch( 283 aggregationData instanceof DistributionData, aggregation, aggregationData); 284 return null; 285 } 286 }, 287 new Function<LastValue, Void>() { 288 @Override 289 public Void apply(LastValue arg) { 290 measure.match( 291 new Function<MeasureDouble, Void>() { 292 @Override 293 public Void apply(MeasureDouble arg) { 294 throwIfAggregationMismatch( 295 aggregationData instanceof LastValueDataDouble, 296 aggregation, 297 aggregationData); 298 return null; 299 } 300 }, 301 new Function<MeasureLong, Void>() { 302 @Override 303 public Void apply(MeasureLong arg) { 304 throwIfAggregationMismatch( 305 aggregationData instanceof LastValueDataLong, aggregation, aggregationData); 306 return null; 307 } 308 }, 309 Functions.</*@Nullable*/ Void>throwAssertionError()); 310 return null; 311 } 312 }, 313 new Function<Aggregation, Void>() { 314 @Override 315 public Void apply(Aggregation arg) { 316 // TODO(songya): remove this once Mean aggregation is completely removed. Before that 317 // we need to continue supporting Mean, since it could still be used by users and some 318 // deprecated RPC views. 319 if (arg instanceof Aggregation.Mean) { 320 throwIfAggregationMismatch( 321 aggregationData instanceof AggregationData.MeanData, 322 aggregation, 323 aggregationData); 324 return null; 325 } 326 throw new AssertionError(); 327 } 328 }); 329 } 330 331 private static void throwIfAggregationMismatch( 332 boolean isValid, Aggregation aggregation, AggregationData aggregationData) { 333 if (!isValid) { 334 throw new IllegalArgumentException( 335 createErrorMessageForAggregation(aggregation, aggregationData)); 336 } 337 } 338 339 private static String createErrorMessageForAggregation( 340 Aggregation aggregation, AggregationData aggregationData) { 341 return "Aggregation and AggregationData types mismatch. " 342 + "Aggregation: " 343 + aggregation.getClass().getSimpleName() 344 + " AggregationData: " 345 + aggregationData.getClass().getSimpleName(); 346 } 347 348 /** 349 * The {@code AggregationWindowData} for a {@link ViewData}. 350 * 351 * @since 0.8 352 * @deprecated since 0.13, please use start and end {@link Timestamp} instead. 353 */ 354 @Deprecated 355 @Immutable 356 public abstract static class AggregationWindowData { 357 358 private AggregationWindowData() {} 359 360 /** 361 * Applies the given match function to the underlying data type. 362 * 363 * @since 0.8 364 */ 365 public abstract <T> T match( 366 Function<? super CumulativeData, T> p0, 367 Function<? super IntervalData, T> p1, 368 Function<? super AggregationWindowData, T> defaultFunction); 369 370 /** 371 * Cumulative {@code AggregationWindowData}. 372 * 373 * @since 0.8 374 * @deprecated since 0.13, please use start and end {@link Timestamp} instead. 375 */ 376 @Deprecated 377 @Immutable 378 @AutoValue 379 @AutoValue.CopyAnnotations 380 public abstract static class CumulativeData extends AggregationWindowData { 381 382 CumulativeData() {} 383 384 /** 385 * Returns the start {@code Timestamp} for a {@link CumulativeData}. 386 * 387 * @return the start {@code Timestamp}. 388 * @since 0.8 389 */ 390 public abstract Timestamp getStart(); 391 392 /** 393 * Returns the end {@code Timestamp} for a {@link CumulativeData}. 394 * 395 * @return the end {@code Timestamp}. 396 * @since 0.8 397 */ 398 public abstract Timestamp getEnd(); 399 400 @Override 401 public final <T> T match( 402 Function<? super CumulativeData, T> p0, 403 Function<? super IntervalData, T> p1, 404 Function<? super AggregationWindowData, T> defaultFunction) { 405 return p0.apply(this); 406 } 407 408 /** 409 * Constructs a new {@link CumulativeData}. 410 * 411 * @since 0.8 412 */ 413 public static CumulativeData create(Timestamp start, Timestamp end) { 414 if (start.compareTo(end) > 0) { 415 throw new IllegalArgumentException("Start time is later than end time."); 416 } 417 return new AutoValue_ViewData_AggregationWindowData_CumulativeData(start, end); 418 } 419 } 420 421 /** 422 * Interval {@code AggregationWindowData}. 423 * 424 * @since 0.8 425 * @deprecated since 0.13, please use start and end {@link Timestamp} instead. 426 */ 427 @Deprecated 428 @Immutable 429 @AutoValue 430 @AutoValue.CopyAnnotations 431 public abstract static class IntervalData extends AggregationWindowData { 432 433 IntervalData() {} 434 435 /** 436 * Returns the end {@code Timestamp} for an {@link IntervalData}. 437 * 438 * @return the end {@code Timestamp}. 439 * @since 0.8 440 */ 441 public abstract Timestamp getEnd(); 442 443 @Override 444 public final <T> T match( 445 Function<? super CumulativeData, T> p0, 446 Function<? super IntervalData, T> p1, 447 Function<? super AggregationWindowData, T> defaultFunction) { 448 return p1.apply(this); 449 } 450 451 /** 452 * Constructs a new {@link IntervalData}. 453 * 454 * @since 0.8 455 */ 456 public static IntervalData create(Timestamp end) { 457 return new AutoValue_ViewData_AggregationWindowData_IntervalData(end); 458 } 459 } 460 } 461 } 462