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.internal.DefaultVisibilityForTesting;
23 import io.opencensus.internal.StringUtils;
24 import io.opencensus.internal.Utils;
25 import io.opencensus.tags.TagKey;
26 import java.util.ArrayList;
27 import java.util.Collections;
28 import java.util.Comparator;
29 import java.util.HashSet;
30 import java.util.List;
31 import javax.annotation.concurrent.Immutable;
32 
33 /**
34  * A View specifies an aggregation and a set of tag keys. The aggregation will be broken down by the
35  * unique set of matching tag values for each measure.
36  *
37  * @since 0.8
38  */
39 @Immutable
40 @AutoValue
41 @AutoValue.CopyAnnotations
42 @SuppressWarnings("deprecation")
43 public abstract class View {
44 
45   @DefaultVisibilityForTesting static final int NAME_MAX_LENGTH = 255;
46 
47   private static final Comparator<TagKey> TAG_KEY_COMPARATOR =
48       new Comparator<TagKey>() {
49         @Override
50         public int compare(TagKey key1, TagKey key2) {
51           return key1.getName().compareTo(key2.getName());
52         }
53       };
54 
View()55   View() {}
56 
57   /**
58    * Name of view. Must be unique.
59    *
60    * @since 0.8
61    */
getName()62   public abstract Name getName();
63 
64   /**
65    * More detailed description, for documentation purposes.
66    *
67    * @since 0.8
68    */
getDescription()69   public abstract String getDescription();
70 
71   /**
72    * Measure type of this view.
73    *
74    * @since 0.8
75    */
getMeasure()76   public abstract Measure getMeasure();
77 
78   /**
79    * The {@link Aggregation} associated with this {@link View}.
80    *
81    * @since 0.8
82    */
getAggregation()83   public abstract Aggregation getAggregation();
84 
85   /**
86    * Columns (a.k.a Tag Keys) to match with the associated {@link Measure}.
87    *
88    * <p>{@link Measure} will be recorded in a "greedy" way. That is, every view aggregates every
89    * measure. This is similar to doing a GROUPBY on view’s columns. Columns must be unique.
90    *
91    * @since 0.8
92    */
getColumns()93   public abstract List<TagKey> getColumns();
94 
95   /**
96    * Returns the time {@link AggregationWindow} for this {@code View}.
97    *
98    * @return the time {@link AggregationWindow}.
99    * @since 0.8
100    * @deprecated since 0.13. In the future all {@link View}s will be cumulative.
101    */
102   @Deprecated
getWindow()103   public abstract AggregationWindow getWindow();
104 
105   /**
106    * Constructs a new {@link View}.
107    *
108    * @param name the {@link Name} of view. Must be unique.
109    * @param description the description of view.
110    * @param measure the {@link Measure} to be aggregated by this view.
111    * @param aggregation the basic {@link Aggregation} that this view will support.
112    * @param columns the {@link TagKey}s that this view will aggregate on. Columns should not contain
113    *     duplicates.
114    * @param window the {@link AggregationWindow} of view.
115    * @return a new {@link View}.
116    * @since 0.8
117    * @deprecated in favor of {@link #create(Name, String, Measure, Aggregation, List)}.
118    */
119   @Deprecated
create( Name name, String description, Measure measure, Aggregation aggregation, List<TagKey> columns, AggregationWindow window)120   public static View create(
121       Name name,
122       String description,
123       Measure measure,
124       Aggregation aggregation,
125       List<TagKey> columns,
126       AggregationWindow window) {
127     Utils.checkArgument(
128         new HashSet<TagKey>(columns).size() == columns.size(), "Columns have duplicate.");
129 
130     List<TagKey> tagKeys = new ArrayList<TagKey>(columns);
131     Collections.sort(tagKeys, TAG_KEY_COMPARATOR);
132     return new AutoValue_View(
133         name, description, measure, aggregation, Collections.unmodifiableList(tagKeys), window);
134   }
135 
136   /**
137    * Constructs a new {@link View}.
138    *
139    * @param name the {@link Name} of view. Must be unique.
140    * @param description the description of view.
141    * @param measure the {@link Measure} to be aggregated by this view.
142    * @param aggregation the basic {@link Aggregation} that this view will support.
143    * @param columns the {@link TagKey}s that this view will aggregate on. Columns should not contain
144    *     duplicates.
145    * @return a new {@link View}.
146    * @since 0.13
147    */
create( Name name, String description, Measure measure, Aggregation aggregation, List<TagKey> columns)148   public static View create(
149       Name name,
150       String description,
151       Measure measure,
152       Aggregation aggregation,
153       List<TagKey> columns) {
154     Utils.checkArgument(
155         new HashSet<TagKey>(columns).size() == columns.size(), "Columns have duplicate.");
156     return create(
157         name, description, measure, aggregation, columns, AggregationWindow.Cumulative.create());
158   }
159 
160   /**
161    * The name of a {@code View}.
162    *
163    * @since 0.8
164    */
165   // This type should be used as the key when associating data with Views.
166   @Immutable
167   @AutoValue
168   public abstract static class Name {
169 
Name()170     Name() {}
171 
172     /**
173      * Returns the name as a {@code String}.
174      *
175      * @return the name as a {@code String}.
176      * @since 0.8
177      */
asString()178     public abstract String asString();
179 
180     /**
181      * Creates a {@code View.Name} from a {@code String}. Should be a ASCII string with a length no
182      * greater than 255 characters.
183      *
184      * <p>Suggested format for name: {@code <web_host>/<path>}.
185      *
186      * @param name the name {@code String}.
187      * @return a {@code View.Name} with the given name {@code String}.
188      * @since 0.8
189      */
create(String name)190     public static Name create(String name) {
191       Utils.checkArgument(
192           StringUtils.isPrintableString(name) && name.length() <= NAME_MAX_LENGTH,
193           "Name should be a ASCII string with a length no greater than 255 characters.");
194       return new AutoValue_View_Name(name);
195     }
196   }
197 
198   /**
199    * The time window for a {@code View}.
200    *
201    * @since 0.8
202    * @deprecated since 0.13. In the future all {@link View}s will be cumulative.
203    */
204   @Deprecated
205   @Immutable
206   public abstract static class AggregationWindow {
207 
AggregationWindow()208     private AggregationWindow() {}
209 
210     /**
211      * Applies the given match function to the underlying data type.
212      *
213      * @since 0.8
214      */
match( Function<? super Cumulative, T> p0, Function<? super Interval, T> p1, Function<? super AggregationWindow, T> defaultFunction)215     public abstract <T> T match(
216         Function<? super Cumulative, T> p0,
217         Function<? super Interval, T> p1,
218         Function<? super AggregationWindow, T> defaultFunction);
219 
220     /**
221      * Cumulative (infinite interval) time {@code AggregationWindow}.
222      *
223      * @since 0.8
224      * @deprecated since 0.13. In the future all {@link View}s will be cumulative.
225      */
226     @Deprecated
227     @Immutable
228     @AutoValue
229     @AutoValue.CopyAnnotations
230     public abstract static class Cumulative extends AggregationWindow {
231 
232       private static final Cumulative CUMULATIVE =
233           new AutoValue_View_AggregationWindow_Cumulative();
234 
Cumulative()235       Cumulative() {}
236 
237       /**
238        * Constructs a cumulative {@code AggregationWindow} that does not have an explicit {@code
239        * Duration}. Instead, cumulative {@code AggregationWindow} always has an interval of infinite
240        * {@code Duration}.
241        *
242        * @return a cumulative {@code AggregationWindow}.
243        * @since 0.8
244        */
create()245       public static Cumulative create() {
246         return CUMULATIVE;
247       }
248 
249       @Override
match( Function<? super Cumulative, T> p0, Function<? super Interval, T> p1, Function<? super AggregationWindow, T> defaultFunction)250       public final <T> T match(
251           Function<? super Cumulative, T> p0,
252           Function<? super Interval, T> p1,
253           Function<? super AggregationWindow, T> defaultFunction) {
254         return p0.apply(this);
255       }
256     }
257 
258     /**
259      * Interval (finite interval) time {@code AggregationWindow}.
260      *
261      * @since 0.8
262      * @deprecated since 0.13. In the future all {@link View}s will be cumulative.
263      */
264     @Deprecated
265     @Immutable
266     @AutoValue
267     @AutoValue.CopyAnnotations
268     public abstract static class Interval extends AggregationWindow {
269 
270       private static final Duration ZERO = Duration.create(0, 0);
271 
Interval()272       Interval() {}
273 
274       /**
275        * Returns the {@code Duration} associated with this {@code Interval}.
276        *
277        * @return a {@code Duration}.
278        * @since 0.8
279        */
getDuration()280       public abstract Duration getDuration();
281 
282       /**
283        * Constructs an interval {@code AggregationWindow} that has a finite explicit {@code
284        * Duration}.
285        *
286        * <p>The {@code Duration} should be able to round to milliseconds. Currently interval window
287        * cannot have smaller {@code Duration} such as microseconds or nanoseconds.
288        *
289        * @return an interval {@code AggregationWindow}.
290        * @since 0.8
291        */
create(Duration duration)292       public static Interval create(Duration duration) {
293         Utils.checkArgument(duration.compareTo(ZERO) > 0, "Duration must be positive");
294         return new AutoValue_View_AggregationWindow_Interval(duration);
295       }
296 
297       @Override
match( Function<? super Cumulative, T> p0, Function<? super Interval, T> p1, Function<? super AggregationWindow, T> defaultFunction)298       public final <T> T match(
299           Function<? super Cumulative, T> p0,
300           Function<? super Interval, T> p1,
301           Function<? super AggregationWindow, T> defaultFunction) {
302         return p1.apply(this);
303       }
304     }
305   }
306 }
307