• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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