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