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