ConfigFactory.java revision b814481ad1f8d0e429d799b1571a6272e1a7f6c5
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.FieldValueMatcher;
31import com.android.internal.os.StatsdConfigProto.AtomMatcher;
32import com.android.internal.os.StatsdConfigProto.SimplePredicate;
33import com.android.internal.os.StatsdConfigProto.StatsdConfig;
34import com.android.internal.os.StatsdConfigProto.TimeUnit;
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 long CONFIG_ID = 123456789;
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, TimeUnit bucket, boolean placebo, boolean includeCount,
87                          boolean includeDuration, boolean includeEvent, boolean includeValue,
88                          boolean includeGauge) {
89        StatsdConfig.Builder config = StatsdConfig.newBuilder()
90            .setId(CONFIG_ID);
91        if (placebo) {
92          replication = 0;  // Config will be empty, aside from a name.
93        }
94        int numMetrics = 0;
95        for (int i = 0; i < replication; i++) {
96            // metrics
97            if (includeEvent) {
98                for (EventMetric metric : mTemplate.getEventMetricList()) {
99                    addEventMetric(metric, i, config);
100                    numMetrics++;
101                }
102            }
103            if (includeCount) {
104                for (CountMetric metric : mTemplate.getCountMetricList()) {
105                    addCountMetric(metric, i, bucket, config);
106                    numMetrics++;
107                }
108            }
109            if (includeDuration) {
110                for (DurationMetric metric : mTemplate.getDurationMetricList()) {
111                    addDurationMetric(metric, i, bucket, config);
112                    numMetrics++;
113                }
114            }
115            if (includeGauge) {
116                for (GaugeMetric metric : mTemplate.getGaugeMetricList()) {
117                    addGaugeMetric(metric, i, bucket, config);
118                    numMetrics++;
119                }
120            }
121            if (includeValue) {
122                for (ValueMetric metric : mTemplate.getValueMetricList()) {
123                    addValueMetric(metric, i, bucket, config);
124                    numMetrics++;
125                }
126            }
127            // predicates
128            for (Predicate predicate : mTemplate.getPredicateList()) {
129              addPredicate(predicate, i, config);
130            }
131            // matchers
132            for (AtomMatcher matcher : mTemplate.getAtomMatcherList()) {
133              addMatcher(matcher, i, config);
134            }
135        }
136
137        Log.d(TAG, "Loadtest config is : " + config.build());
138        Log.d(TAG, "Generated config has " + numMetrics + " metrics");
139
140        return config.build().toByteArray();
141    }
142
143    /**
144     * Creates {@link MetricConditionLink}s that are identical to the one passed to this method,
145     * except that the names are appended with the provided suffix.
146     */
147    private List<MetricConditionLink> getLinks(
148        List<MetricConditionLink> links, int suffix) {
149        List<MetricConditionLink> newLinks = new ArrayList();
150        for (MetricConditionLink link : links) {
151            newLinks.add(link.toBuilder()
152                .setCondition(link.getCondition() + suffix)
153                .build());
154        }
155        return newLinks;
156    }
157
158    /**
159     * Creates an {@link EventMetric} based on the template. Makes sure that all names are appended
160     * with the provided suffix. Then adds that metric to the config.
161     */
162    private void addEventMetric(EventMetric template, int suffix, StatsdConfig.Builder config) {
163        EventMetric.Builder metric = template.toBuilder()
164            .setId(template.getId() + suffix)
165            .setWhat(template.getWhat() + suffix);
166        if (template.hasCondition()) {
167            metric.setCondition(template.getCondition() + suffix);
168        }
169        if (template.getLinksCount() > 0) {
170            List<MetricConditionLink> links = getLinks(template.getLinksList(), suffix);
171            metric.clearLinks();
172            metric.addAllLinks(links);
173        }
174        config.addEventMetric(metric);
175    }
176
177    /**
178     * Creates a {@link CountMetric} based on the template. Makes sure that all names are appended
179     * with the provided suffix, and overrides the bucket size. Then adds that metric to the config.
180     */
181    private void addCountMetric(CountMetric template, int suffix, TimeUnit bucket,
182        StatsdConfig.Builder config) {
183        CountMetric.Builder metric = template.toBuilder()
184            .setId(template.getId() + suffix)
185            .setWhat(template.getWhat() + suffix);
186        if (template.hasCondition()) {
187            metric.setCondition(template.getCondition() + suffix);
188        }
189        if (template.getLinksCount() > 0) {
190            List<MetricConditionLink> links = getLinks(template.getLinksList(), suffix);
191            metric.clearLinks();
192            metric.addAllLinks(links);
193        }
194        metric.setBucket(bucket);
195        config.addCountMetric(metric);
196    }
197
198    /**
199     * Creates a {@link DurationMetric} based on the template. Makes sure that all names are appended
200     * with the provided suffix, and overrides the bucket size. Then adds that metric to the config.
201     */
202    private void addDurationMetric(DurationMetric template, int suffix, TimeUnit bucket,
203        StatsdConfig.Builder config) {
204        DurationMetric.Builder metric = template.toBuilder()
205            .setId(template.getId() + suffix)
206            .setWhat(template.getWhat() + suffix);
207        if (template.hasCondition()) {
208            metric.setCondition(template.getCondition() + suffix);
209        }
210        if (template.getLinksCount() > 0) {
211            List<MetricConditionLink> links = getLinks(template.getLinksList(), suffix);
212            metric.clearLinks();
213            metric.addAllLinks(links);
214        }
215        metric.setBucket(bucket);
216        config.addDurationMetric(metric);
217    }
218
219    /**
220     * Creates a {@link GaugeMetric} based on the template. Makes sure that all names are appended
221     * with the provided suffix, and overrides the bucket size. Then adds that metric to the config.
222     */
223    private void addGaugeMetric(GaugeMetric template, int suffix, TimeUnit bucket,
224        StatsdConfig.Builder config) {
225        GaugeMetric.Builder metric = template.toBuilder()
226            .setId(template.getId() + suffix)
227            .setWhat(template.getWhat() + suffix);
228        if (template.hasCondition()) {
229            metric.setCondition(template.getCondition() + suffix);
230        }
231        if (template.getLinksCount() > 0) {
232            List<MetricConditionLink> links = getLinks(template.getLinksList(), suffix);
233            metric.clearLinks();
234            metric.addAllLinks(links);
235        }
236        metric.setBucket(bucket);
237        config.addGaugeMetric(metric);
238    }
239
240    /**
241     * Creates a {@link ValueMetric} based on the template. Makes sure that all names are appended
242     * with the provided suffix, and overrides the bucket size. Then adds that metric to the config.
243     */
244    private void addValueMetric(ValueMetric template, int suffix, TimeUnit bucket,
245        StatsdConfig.Builder config) {
246        ValueMetric.Builder metric = template.toBuilder()
247            .setId(template.getId() + suffix)
248            .setWhat(template.getWhat() + suffix);
249        if (template.hasCondition()) {
250            metric.setCondition(template.getCondition() + suffix);
251        }
252        if (template.getLinksCount() > 0) {
253            List<MetricConditionLink> links = getLinks(template.getLinksList(), suffix);
254            metric.clearLinks();
255            metric.addAllLinks(links);
256        }
257        metric.setBucket(bucket);
258        config.addValueMetric(metric);
259    }
260
261    /**
262     * Creates a {@link Predicate} based on the template. Makes sure that all names
263     * are appended with the provided suffix. Then adds that predicate to the config.
264     */
265    private void addPredicate(Predicate template, int suffix, StatsdConfig.Builder config) {
266        Predicate.Builder predicate = template.toBuilder()
267            .setId(template.getId() + suffix);
268        if (template.hasCombination()) {
269            Predicate.Combination.Builder cb = template.getCombination().toBuilder()
270                .clearPredicate();
271            for (long child : template.getCombination().getPredicateList()) {
272                cb.addPredicate(child + suffix);
273            }
274            predicate.setCombination(cb.build());
275        }
276        if (template.hasSimplePredicate()) {
277            SimplePredicate.Builder sc = template.getSimplePredicate().toBuilder()
278                .setStart(template.getSimplePredicate().getStart() + suffix)
279                .setStop(template.getSimplePredicate().getStop() + suffix);
280            if (template.getSimplePredicate().hasStopAll()) {
281                sc.setStopAll(template.getSimplePredicate().getStopAll() + suffix);
282            }
283            predicate.setSimplePredicate(sc.build());
284        }
285        config.addPredicate(predicate);
286    }
287
288    /**
289     * Creates a {@link AtomMatcher} based on the template. Makes sure that all names
290     * are appended with the provided suffix. Then adds that matcher to the config.
291     */
292    private void addMatcher(AtomMatcher template, int suffix, StatsdConfig.Builder config) {
293        AtomMatcher.Builder matcher = template.toBuilder()
294            .setId(template.getId() + suffix);
295        if (template.hasCombination()) {
296            AtomMatcher.Combination.Builder cb = template.getCombination().toBuilder()
297                .clearMatcher();
298            for (long child : template.getCombination().getMatcherList()) {
299                cb.addMatcher(child + suffix);
300            }
301            matcher.setCombination(cb);
302        }
303        config.addAtomMatcher(matcher);
304    }
305}
306