ConfigFactory.java revision 9d25218985ba8ea944b4a51d194744b5a85a1105
1/* 2 * Copyright (C) 2017 The Android Open Source Project 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 */ 16package com.android.statsd.loadtest; 17 18import android.content.Context; 19import android.content.res.Resources; 20import android.util.Log; 21 22import com.android.internal.os.StatsdConfigProto.Bucket; 23import com.android.internal.os.StatsdConfigProto.Predicate; 24import com.android.internal.os.StatsdConfigProto.CountMetric; 25import com.android.internal.os.StatsdConfigProto.DurationMetric; 26import com.android.internal.os.StatsdConfigProto.MetricConditionLink; 27import com.android.internal.os.StatsdConfigProto.EventMetric; 28import com.android.internal.os.StatsdConfigProto.GaugeMetric; 29import com.android.internal.os.StatsdConfigProto.ValueMetric; 30import com.android.internal.os.StatsdConfigProto.KeyMatcher; 31import com.android.internal.os.StatsdConfigProto.KeyValueMatcher; 32import com.android.internal.os.StatsdConfigProto.AtomMatcher; 33import com.android.internal.os.StatsdConfigProto.SimplePredicate; 34import com.android.internal.os.StatsdConfigProto.StatsdConfig; 35 36import java.io.InputStream; 37import java.io.IOException; 38import java.util.ArrayList; 39import java.util.List; 40 41/** 42 * Creates StatsdConfig protos for loadtesting. 43 */ 44public class ConfigFactory { 45 public static final String CONFIG_NAME = "LOADTEST"; 46 47 private static final String TAG = "loadtest.ConfigFactory"; 48 49 private final StatsdConfig mTemplate; 50 51 public ConfigFactory(Context context) { 52 // Read the config template from the resoures. 53 Resources res = context.getResources(); 54 byte[] template = null; 55 StatsdConfig templateProto = null; 56 try { 57 InputStream inputStream = res.openRawResource(R.raw.loadtest_config); 58 template = new byte[inputStream.available()]; 59 inputStream.read(template); 60 templateProto = StatsdConfig.parseFrom(template); 61 } catch (IOException e) { 62 Log.e(TAG, "Unable to read or parse loadtest config template. Using an empty config."); 63 } 64 mTemplate = templateProto == null ? StatsdConfig.newBuilder().build() : templateProto; 65 66 Log.d(TAG, "Loadtest template config: " + mTemplate); 67 } 68 69 /** 70 * Generates a config. 71 * 72 * All configs are based on the same template. 73 * That template is designed to make the most use of the set of atoms that {@code SequencePusher} 74 * pushes, and to exercise as many of the metrics features as possible. 75 * Furthermore, by passing a replication factor to this method, one can artificially inflate 76 * the number of metrics in the config. One can also adjust the bucket size for aggregate 77 * metrics. 78 * 79 * @param replication The number of times each metric is replicated in the config. 80 * If the config template has n metrics, the generated config will have n * replication 81 * ones 82 * @param bucketMillis The bucket size, in milliseconds, for aggregate metrics 83 * @param placebo If true, only return an empty config 84 * @return The serialized config 85 */ 86 public byte[] getConfig(int replication, long bucketMillis, boolean placebo) { 87 StatsdConfig.Builder config = StatsdConfig.newBuilder() 88 .setName(CONFIG_NAME); 89 if (placebo) { 90 replication = 0; // Config will be empty, aside from a name. 91 } 92 int numMetrics = 0; 93 for (int i = 0; i < replication; i++) { 94 // metrics 95 for (EventMetric metric : mTemplate.getEventMetricList()) { 96 addEventMetric(metric, i, config); 97 numMetrics++; 98 } 99 for (CountMetric metric : mTemplate.getCountMetricList()) { 100 addCountMetric(metric, i, bucketMillis, config); 101 numMetrics++; 102 } 103 for (DurationMetric metric : mTemplate.getDurationMetricList()) { 104 addDurationMetric(metric, i, bucketMillis, config); 105 numMetrics++; 106 } 107 for (GaugeMetric metric : mTemplate.getGaugeMetricList()) { 108 addGaugeMetric(metric, i, bucketMillis, config); 109 numMetrics++; 110 } 111 for (ValueMetric metric : mTemplate.getValueMetricList()) { 112 addValueMetric(metric, i, bucketMillis, config); 113 numMetrics++; 114 } 115 // predicates 116 for (Predicate predicate : mTemplate.getPredicateList()) { 117 addPredicate(predicate, i, config); 118 } 119 // matchers 120 for (AtomMatcher matcher : mTemplate.getAtomMatcherList()) { 121 addMatcher(matcher, i, config); 122 } 123 } 124 125 Log.d(TAG, "Loadtest config is : " + config.build()); 126 Log.d(TAG, "Generated config has " + numMetrics + " metrics"); 127 128 return config.build().toByteArray(); 129 } 130 131 /** 132 * Creates {@link MetricConditionLink}s that are identical to the one passed to this method, 133 * except that the names are appended with the provided suffix. 134 */ 135 private List<MetricConditionLink> getLinks( 136 List<MetricConditionLink> links, int suffix) { 137 List<MetricConditionLink> newLinks = new ArrayList(); 138 for (MetricConditionLink link : links) { 139 newLinks.add(link.toBuilder() 140 .setCondition(link.getCondition() + suffix) 141 .build()); 142 } 143 return newLinks; 144 } 145 146 /** 147 * Creates an {@link EventMetric} based on the template. Makes sure that all names are appended 148 * with the provided suffix. Then adds that metric to the config. 149 */ 150 private void addEventMetric(EventMetric template, int suffix, StatsdConfig.Builder config) { 151 EventMetric.Builder metric = template.toBuilder() 152 .setName(template.getName() + suffix) 153 .setWhat(template.getWhat() + suffix); 154 if (template.hasCondition()) { 155 metric.setCondition(template.getCondition() + suffix); 156 } 157 if (template.getLinksCount() > 0) { 158 List<MetricConditionLink> links = getLinks(template.getLinksList(), suffix); 159 metric.clearLinks(); 160 metric.addAllLinks(links); 161 } 162 config.addEventMetric(metric); 163 } 164 165 private Bucket getBucket(long bucketMillis) { 166 return Bucket.newBuilder() 167 .setBucketSizeMillis(bucketMillis) 168 .build(); 169 } 170 171 /** 172 * Creates a {@link CountMetric} based on the template. Makes sure that all names are appended 173 * with the provided suffix, and overrides the bucket size. Then adds that metric to the config. 174 */ 175 private void addCountMetric(CountMetric template, int suffix, long bucketMillis, 176 StatsdConfig.Builder config) { 177 CountMetric.Builder metric = template.toBuilder() 178 .setName(template.getName() + suffix) 179 .setWhat(template.getWhat() + suffix); 180 if (template.hasCondition()) { 181 metric.setCondition(template.getCondition() + suffix); 182 } 183 if (template.getLinksCount() > 0) { 184 List<MetricConditionLink> links = getLinks(template.getLinksList(), suffix); 185 metric.clearLinks(); 186 metric.addAllLinks(links); 187 } 188 metric.setBucket(getBucket(bucketMillis)); 189 config.addCountMetric(metric); 190 } 191 192 /** 193 * Creates a {@link DurationMetric} based on the template. Makes sure that all names are appended 194 * with the provided suffix, and overrides the bucket size. Then adds that metric to the config. 195 */ 196 private void addDurationMetric(DurationMetric template, int suffix, long bucketMillis, 197 StatsdConfig.Builder config) { 198 DurationMetric.Builder metric = template.toBuilder() 199 .setName(template.getName() + suffix) 200 .setWhat(template.getWhat() + suffix); 201 if (template.hasCondition()) { 202 metric.setCondition(template.getCondition() + suffix); 203 } 204 if (template.getLinksCount() > 0) { 205 List<MetricConditionLink> links = getLinks(template.getLinksList(), suffix); 206 metric.clearLinks(); 207 metric.addAllLinks(links); 208 } 209 metric.setBucket(getBucket(bucketMillis)); 210 config.addDurationMetric(metric); 211 } 212 213 /** 214 * Creates a {@link GaugeMetric} based on the template. Makes sure that all names are appended 215 * with the provided suffix, and overrides the bucket size. Then adds that metric to the config. 216 */ 217 private void addGaugeMetric(GaugeMetric template, int suffix, long bucketMillis, 218 StatsdConfig.Builder config) { 219 GaugeMetric.Builder metric = template.toBuilder() 220 .setName(template.getName() + suffix) 221 .setWhat(template.getWhat() + suffix); 222 if (template.hasCondition()) { 223 metric.setCondition(template.getCondition() + suffix); 224 } 225 if (template.getLinksCount() > 0) { 226 List<MetricConditionLink> links = getLinks(template.getLinksList(), suffix); 227 metric.clearLinks(); 228 metric.addAllLinks(links); 229 } 230 metric.setBucket(getBucket(bucketMillis)); 231 config.addGaugeMetric(metric); 232 } 233 234 /** 235 * Creates a {@link ValueMetric} based on the template. Makes sure that all names are appended 236 * with the provided suffix, and overrides the bucket size. Then adds that metric to the config. 237 */ 238 private void addValueMetric(ValueMetric template, int suffix, long bucketMillis, 239 StatsdConfig.Builder config) { 240 ValueMetric.Builder metric = template.toBuilder() 241 .setName(template.getName() + suffix) 242 .setWhat(template.getWhat() + suffix); 243 if (template.hasCondition()) { 244 metric.setCondition(template.getCondition() + suffix); 245 } 246 if (template.getLinksCount() > 0) { 247 List<MetricConditionLink> links = getLinks(template.getLinksList(), suffix); 248 metric.clearLinks(); 249 metric.addAllLinks(links); 250 } 251 metric.setBucket(getBucket(bucketMillis)); 252 config.addValueMetric(metric); 253 } 254 255 /** 256 * Creates a {@link Predicate} based on the template. Makes sure that all names 257 * are appended with the provided suffix. Then adds that predicate to the config. 258 */ 259 private void addPredicate(Predicate template, int suffix, StatsdConfig.Builder config) { 260 Predicate.Builder predicate = template.toBuilder() 261 .setName(template.getName() + suffix); 262 if (template.hasCombination()) { 263 Predicate.Combination.Builder cb = template.getCombination().toBuilder() 264 .clearPredicate(); 265 for (String child : template.getCombination().getPredicateList()) { 266 cb.addPredicate(child + suffix); 267 } 268 predicate.setCombination(cb.build()); 269 } 270 if (template.hasSimplePredicate()) { 271 SimplePredicate.Builder sc = template.getSimplePredicate().toBuilder() 272 .setStart(template.getSimplePredicate().getStart() + suffix) 273 .setStop(template.getSimplePredicate().getStop() + suffix); 274 if (template.getSimplePredicate().hasStopAll()) { 275 sc.setStopAll(template.getSimplePredicate().getStopAll() + suffix); 276 } 277 predicate.setSimplePredicate(sc.build()); 278 } 279 config.addPredicate(predicate); 280 } 281 282 /** 283 * Creates a {@link AtomMatcher} based on the template. Makes sure that all names 284 * are appended with the provided suffix. Then adds that matcher to the config. 285 */ 286 private void addMatcher(AtomMatcher template, int suffix, StatsdConfig.Builder config) { 287 AtomMatcher.Builder matcher = template.toBuilder() 288 .setName(template.getName() + suffix); 289 if (template.hasCombination()) { 290 AtomMatcher.Combination.Builder cb = template.getCombination().toBuilder() 291 .clearMatcher(); 292 for (String child : template.getCombination().getMatcherList()) { 293 cb.addMatcher(child + suffix); 294 } 295 matcher.setCombination(cb); 296 } 297 config.addAtomMatcher(matcher); 298 } 299} 300