• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2018, 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 com.google.common.annotations.VisibleForTesting;
20 import com.google.common.collect.ImmutableMap;
21 import com.google.common.collect.Maps;
22 import io.opencensus.common.Function;
23 import io.opencensus.common.Functions;
24 import io.opencensus.implcore.stats.MutableAggregation.MutableCount;
25 import io.opencensus.implcore.stats.MutableAggregation.MutableDistribution;
26 import io.opencensus.implcore.stats.MutableAggregation.MutableLastValueDouble;
27 import io.opencensus.implcore.stats.MutableAggregation.MutableLastValueLong;
28 import io.opencensus.implcore.stats.MutableAggregation.MutableMean;
29 import io.opencensus.implcore.stats.MutableAggregation.MutableSumDouble;
30 import io.opencensus.implcore.stats.MutableAggregation.MutableSumLong;
31 import io.opencensus.implcore.tags.TagMapImpl;
32 import io.opencensus.implcore.tags.TagValueWithMetadata;
33 import io.opencensus.stats.Aggregation;
34 import io.opencensus.stats.Aggregation.Count;
35 import io.opencensus.stats.Aggregation.Distribution;
36 import io.opencensus.stats.Aggregation.LastValue;
37 import io.opencensus.stats.Aggregation.Sum;
38 import io.opencensus.stats.AggregationData;
39 import io.opencensus.stats.Measure;
40 import io.opencensus.stats.Measure.MeasureDouble;
41 import io.opencensus.stats.Measure.MeasureLong;
42 import io.opencensus.stats.Measurement;
43 import io.opencensus.stats.Measurement.MeasurementDouble;
44 import io.opencensus.stats.Measurement.MeasurementLong;
45 import io.opencensus.tags.InternalUtils;
46 import io.opencensus.tags.Tag;
47 import io.opencensus.tags.TagContext;
48 import io.opencensus.tags.TagKey;
49 import io.opencensus.tags.TagValue;
50 import java.util.ArrayList;
51 import java.util.Iterator;
52 import java.util.List;
53 import java.util.Map;
54 import java.util.Map.Entry;
55 
56 /*>>>
57 import org.checkerframework.checker.nullness.qual.Nullable;
58 */
59 
60 @SuppressWarnings("deprecation")
61 /* Common static utilities for stats recording. */
62 final class RecordUtils {
63 
64   @javax.annotation.Nullable @VisibleForTesting static final TagValue UNKNOWN_TAG_VALUE = null;
65 
66   // TODO(songy23): remove the mapping once we completely remove the deprecated RPC constants.
67   @VisibleForTesting static final TagKey RPC_STATUS = TagKey.create("canonical_status");
68   @VisibleForTesting static final TagKey RPC_METHOD = TagKey.create("method");
69   @VisibleForTesting static final TagKey GRPC_CLIENT_STATUS = TagKey.create("grpc_client_status");
70   @VisibleForTesting static final TagKey GRPC_CLIENT_METHOD = TagKey.create("grpc_client_method");
71   @VisibleForTesting static final TagKey GRPC_SERVER_STATUS = TagKey.create("grpc_server_status");
72   @VisibleForTesting static final TagKey GRPC_SERVER_METHOD = TagKey.create("grpc_server_method");
73   private static final Map<TagKey, TagKey[]> RPC_TAG_MAPPINGS =
74       ImmutableMap.<TagKey, TagKey[]>builder()
75           .put(RPC_STATUS, new TagKey[] {GRPC_CLIENT_STATUS, GRPC_SERVER_STATUS})
76           .put(RPC_METHOD, new TagKey[] {GRPC_CLIENT_METHOD, GRPC_SERVER_METHOD})
77           .build();
78 
getTagMap(TagContext ctx)79   static Map<TagKey, TagValueWithMetadata> getTagMap(TagContext ctx) {
80     if (ctx instanceof TagMapImpl) {
81       return ((TagMapImpl) ctx).getTags();
82     }
83     Map<TagKey, TagValueWithMetadata> tags = Maps.newHashMap();
84     for (Iterator<Tag> i = InternalUtils.getTags(ctx); i.hasNext(); ) {
85       Tag tag = i.next();
86       tags.put(tag.getKey(), TagValueWithMetadata.create(tag.getValue(), tag.getTagMetadata()));
87     }
88     return tags;
89   }
90 
91   @VisibleForTesting
getTagValues( Map<? extends TagKey, TagValueWithMetadata> tags, List<? extends TagKey> columns)92   static List</*@Nullable*/ TagValue> getTagValues(
93       Map<? extends TagKey, TagValueWithMetadata> tags, List<? extends TagKey> columns) {
94     List</*@Nullable*/ TagValue> tagValues = new ArrayList</*@Nullable*/ TagValue>(columns.size());
95     // Record all the measures in a "Greedy" way.
96     // Every view aggregates every measure. This is similar to doing a GROUPBY view’s keys.
97     for (int i = 0; i < columns.size(); ++i) {
98       TagKey tagKey = columns.get(i);
99       if (!tags.containsKey(tagKey)) {
100         @javax.annotation.Nullable TagValue tagValue = UNKNOWN_TAG_VALUE;
101         TagKey[] newKeys = RPC_TAG_MAPPINGS.get(tagKey);
102         if (newKeys != null) {
103           tagValue = getTagValueForDeprecatedRpcTag(tags, newKeys);
104         }
105         tagValues.add(tagValue);
106       } else {
107         tagValues.add(tags.get(tagKey).getTagValue());
108       }
109     }
110     return tagValues;
111   }
112 
113   // TODO(songy23): remove the mapping once we completely remove the deprecated RPC constants.
114   @javax.annotation.Nullable
getTagValueForDeprecatedRpcTag( Map<? extends TagKey, TagValueWithMetadata> tags, TagKey[] newKeys)115   private static TagValue getTagValueForDeprecatedRpcTag(
116       Map<? extends TagKey, TagValueWithMetadata> tags, TagKey[] newKeys) {
117     for (TagKey newKey : newKeys) {
118       TagValueWithMetadata valueWithMetadata = tags.get(newKey);
119       if (valueWithMetadata != null) {
120         return valueWithMetadata.getTagValue();
121       }
122     }
123     return UNKNOWN_TAG_VALUE;
124   }
125 
126   /**
127    * Create an empty {@link MutableAggregation} based on the given {@link Aggregation}.
128    *
129    * @param aggregation {@code Aggregation}.
130    * @return an empty {@code MutableAggregation}.
131    */
132   @VisibleForTesting
createMutableAggregation( Aggregation aggregation, final Measure measure)133   static MutableAggregation createMutableAggregation(
134       Aggregation aggregation, final Measure measure) {
135     return aggregation.match(
136         new Function<Sum, MutableAggregation>() {
137           @Override
138           public MutableAggregation apply(Sum arg) {
139             return measure.match(
140                 CreateMutableSumDouble.INSTANCE,
141                 CreateMutableSumLong.INSTANCE,
142                 Functions.<MutableAggregation>throwAssertionError());
143           }
144         },
145         CreateMutableCount.INSTANCE,
146         CreateMutableDistribution.INSTANCE,
147         new Function<LastValue, MutableAggregation>() {
148           @Override
149           public MutableAggregation apply(LastValue arg) {
150             return measure.match(
151                 CreateMutableLastValueDouble.INSTANCE,
152                 CreateMutableLastValueLong.INSTANCE,
153                 Functions.<MutableAggregation>throwAssertionError());
154           }
155         },
156         AggregationDefaultFunction.INSTANCE);
157   }
158 
159   // Covert a mapping from TagValues to MutableAggregation, to a mapping from TagValues to
160   // AggregationData.
161   static <T> Map<T, AggregationData> createAggregationMap(
162       Map<T, MutableAggregation> tagValueAggregationMap, Measure measure) {
163     Map<T, AggregationData> map = Maps.newHashMap();
164     for (Entry<T, MutableAggregation> entry : tagValueAggregationMap.entrySet()) {
165       map.put(entry.getKey(), entry.getValue().toAggregationData());
166     }
167     return map;
168   }
169 
170   static double getDoubleValueFromMeasurement(Measurement measurement) {
171     return measurement.match(
172         GET_VALUE_FROM_MEASUREMENT_DOUBLE,
173         GET_VALUE_FROM_MEASUREMENT_LONG,
174         Functions.<Double>throwAssertionError());
175   }
176 
177   // static inner Function classes
178 
179   private static final Function<MeasurementDouble, Double> GET_VALUE_FROM_MEASUREMENT_DOUBLE =
180       new Function<MeasurementDouble, Double>() {
181         @Override
182         public Double apply(MeasurementDouble arg) {
183           return arg.getValue();
184         }
185       };
186 
187   private static final Function<MeasurementLong, Double> GET_VALUE_FROM_MEASUREMENT_LONG =
188       new Function<MeasurementLong, Double>() {
189         @Override
190         public Double apply(MeasurementLong arg) {
191           // TODO: consider checking truncation here.
192           return (double) arg.getValue();
193         }
194       };
195 
196   private static final class CreateMutableSumDouble
197       implements Function<MeasureDouble, MutableAggregation> {
198     @Override
199     public MutableAggregation apply(MeasureDouble arg) {
200       return MutableSumDouble.create();
201     }
202 
203     private static final CreateMutableSumDouble INSTANCE = new CreateMutableSumDouble();
204   }
205 
206   private static final class CreateMutableSumLong
207       implements Function<MeasureLong, MutableAggregation> {
208     @Override
209     public MutableAggregation apply(MeasureLong arg) {
210       return MutableSumLong.create();
211     }
212 
213     private static final CreateMutableSumLong INSTANCE = new CreateMutableSumLong();
214   }
215 
216   private static final class CreateMutableCount implements Function<Count, MutableAggregation> {
217     @Override
218     public MutableAggregation apply(Count arg) {
219       return MutableCount.create();
220     }
221 
222     private static final CreateMutableCount INSTANCE = new CreateMutableCount();
223   }
224 
225   // TODO(songya): remove this once Mean aggregation is completely removed. Before that
226   // we need to continue supporting Mean, since it could still be used by users and some
227   // deprecated RPC views.
228   private static final class AggregationDefaultFunction
229       implements Function<Aggregation, MutableAggregation> {
230     @Override
231     public MutableAggregation apply(Aggregation arg) {
232       if (arg instanceof Aggregation.Mean) {
233         return MutableMean.create();
234       }
235       throw new IllegalArgumentException("Unknown Aggregation.");
236     }
237 
238     private static final AggregationDefaultFunction INSTANCE = new AggregationDefaultFunction();
239   }
240 
241   private static final class CreateMutableDistribution
242       implements Function<Distribution, MutableAggregation> {
243     @Override
244     public MutableAggregation apply(Distribution arg) {
245       return MutableDistribution.create(arg.getBucketBoundaries());
246     }
247 
248     private static final CreateMutableDistribution INSTANCE = new CreateMutableDistribution();
249   }
250 
251   private static final class CreateMutableLastValueDouble
252       implements Function<MeasureDouble, MutableAggregation> {
253     @Override
254     public MutableAggregation apply(MeasureDouble arg) {
255       return MutableLastValueDouble.create();
256     }
257 
258     private static final CreateMutableLastValueDouble INSTANCE = new CreateMutableLastValueDouble();
259   }
260 
261   private static final class CreateMutableLastValueLong
262       implements Function<MeasureLong, MutableAggregation> {
263     @Override
264     public MutableAggregation apply(MeasureLong arg) {
265       return MutableLastValueLong.create();
266     }
267 
268     private static final CreateMutableLastValueLong INSTANCE = new CreateMutableLastValueLong();
269   }
270 
271   private RecordUtils() {}
272 }
273