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