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