blob: 28cb503e2bc8256ba9a890414050b420abd6634e [file] [log] [blame]
Yao Chen44cf27c2017-09-14 22:32:50 -07001/*
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 */
16
Yao Chen44cf27c2017-09-14 22:32:50 -070017#define DEBUG true // STOPSHIP if true
Joe Onorato9fc9edf2017-10-15 20:08:52 -070018#include "Log.h"
Yao Chen44cf27c2017-09-14 22:32:50 -070019
Bookatza4bc9c42017-10-04 11:45:57 -070020#include "CountAnomalyTracker.h"
Yao Chen729093d2017-10-16 10:33:26 -070021#include "CountMetricProducer.h"
22#include "stats_util.h"
Yao Chen44cf27c2017-09-14 22:32:50 -070023
24#include <cutils/log.h>
25#include <limits.h>
26#include <stdlib.h>
27
Yao Chen729093d2017-10-16 10:33:26 -070028using std::map;
29using std::string;
Yao Chen44cf27c2017-09-14 22:32:50 -070030using std::unordered_map;
Yao Chen729093d2017-10-16 10:33:26 -070031using std::vector;
Yao Chen44cf27c2017-09-14 22:32:50 -070032
33namespace android {
34namespace os {
35namespace statsd {
36
Yao Chen729093d2017-10-16 10:33:26 -070037// TODO: add back AnomalyTracker.
38CountMetricProducer::CountMetricProducer(const CountMetric& metric, const int conditionIndex,
39 const sp<ConditionWizard>& wizard)
40 // TODO: Pass in the start time from MetricsManager, instead of calling time() here.
41 : MetricProducer((time(nullptr) * NANO_SECONDS_IN_A_SECOND), conditionIndex, wizard),
42 mMetric(metric),
Bookatza4bc9c42017-10-04 11:45:57 -070043 // TODO: read mAnomalyTracker parameters from config file.
Yao Chen729093d2017-10-16 10:33:26 -070044 mAnomalyTracker(6, 10) {
Yao Chen44cf27c2017-09-14 22:32:50 -070045 // TODO: evaluate initial conditions. and set mConditionMet.
46 if (metric.has_bucket() && metric.bucket().has_bucket_size_millis()) {
Yao Chen729093d2017-10-16 10:33:26 -070047 mBucketSizeNs = metric.bucket().bucket_size_millis() * 1000 * 1000;
Yao Chen44cf27c2017-09-14 22:32:50 -070048 } else {
Yao Chen729093d2017-10-16 10:33:26 -070049 mBucketSizeNs = LLONG_MAX;
Yao Chen44cf27c2017-09-14 22:32:50 -070050 }
51
Yao Chen729093d2017-10-16 10:33:26 -070052 // TODO: use UidMap if uid->pkg_name is required
53 mDimension.insert(mDimension.begin(), metric.dimension().begin(), metric.dimension().end());
54
55 if (metric.links().size() > 0) {
56 mConditionLinks.insert(mConditionLinks.begin(), metric.links().begin(),
57 metric.links().end());
58 mConditionSliced = true;
59 }
60
61 VLOG("metric %lld created. bucket size %lld start_time: %lld", metric.metric_id(),
62 (long long)mBucketSizeNs, (long long)mStartTimeNs);
Yao Chen44cf27c2017-09-14 22:32:50 -070063}
64
Yao Chen44cf27c2017-09-14 22:32:50 -070065CountMetricProducer::~CountMetricProducer() {
66 VLOG("~CountMetricProducer() called");
67}
68
69void CountMetricProducer::finish() {
70 // TODO: write the StatsLogReport to dropbox using
71 // DropboxWriter.
Yao Chen44cf27c2017-09-14 22:32:50 -070072}
73
Yao Chen729093d2017-10-16 10:33:26 -070074static void addSlicedCounterToReport(StatsLogReport_CountMetricDataWrapper& wrapper,
75 const vector<KeyValuePair>& key,
76 const vector<CountBucketInfo>& buckets) {
77 CountMetricData* data = wrapper.add_data();
78 for (const auto& kv : key) {
79 data->add_dimension()->CopyFrom(kv);
80 }
81 for (const auto& bucket : buckets) {
82 data->add_bucket_info()->CopyFrom(bucket);
83 VLOG("\t bucket [%lld - %lld] count: %lld", bucket.start_bucket_nanos(),
84 bucket.end_bucket_nanos(), bucket.count());
85 }
86}
87
88void CountMetricProducer::onSlicedConditionMayChange() {
89 VLOG("Metric %lld onSlicedConditionMayChange", mMetric.metric_id());
90}
91
92StatsLogReport CountMetricProducer::onDumpReport() {
93 VLOG("metric %lld dump report now...", mMetric.metric_id());
94
95 StatsLogReport report;
96 report.set_metric_id(mMetric.metric_id());
97 report.set_start_report_nanos(mStartTimeNs);
98
99 // Dump current bucket if it's stale.
100 // If current bucket is still on-going, don't force dump current bucket.
101 // In finish(), We can force dump current bucket.
102 flushCounterIfNeeded(time(nullptr) * NANO_SECONDS_IN_A_SECOND);
103 report.set_end_report_nanos(mCurrentBucketStartTimeNs);
104
105 StatsLogReport_CountMetricDataWrapper* wrapper = report.mutable_count_metrics();
106
107 for (const auto& pair : mPastBuckets) {
108 const HashableDimensionKey& hashableKey = pair.first;
109 auto it = mDimensionKeyMap.find(hashableKey);
110 if (it == mDimensionKeyMap.end()) {
111 ALOGE("Dimension key %s not found?!?! skip...", hashableKey.c_str());
112 continue;
113 }
114
115 VLOG(" dimension key %s", hashableKey.c_str());
116 addSlicedCounterToReport(*wrapper, it->second, pair.second);
117 }
118 return report;
119 // TODO: Clear mPastBuckets, mDimensionKeyMap once the report is dumped.
Yao Chen44cf27c2017-09-14 22:32:50 -0700120}
121
Yao Chencaf339d2017-10-06 16:01:10 -0700122void CountMetricProducer::onConditionChanged(const bool conditionMet) {
Yao Chen729093d2017-10-16 10:33:26 -0700123 VLOG("Metric %lld onConditionChanged", mMetric.metric_id());
Yao Chencaf339d2017-10-06 16:01:10 -0700124 mCondition = conditionMet;
125}
126
Yao Chenb7041772017-10-20 16:59:25 -0700127void CountMetricProducer::onMatchedLogEventInternal(
128 const size_t matcherIndex, const HashableDimensionKey& eventKey,
129 const map<string, HashableDimensionKey>& conditionKey, bool condition,
130 const LogEvent& event) {
Yao Chen729093d2017-10-16 10:33:26 -0700131 uint64_t eventTimeNs = event.GetTimestampNs();
Yao Chen44cf27c2017-09-14 22:32:50 -0700132
Yao Chen729093d2017-10-16 10:33:26 -0700133 flushCounterIfNeeded(eventTimeNs);
134
Yao Chenb7041772017-10-20 16:59:25 -0700135 if (condition == false) {
136 return;
Yao Chen44cf27c2017-09-14 22:32:50 -0700137 }
Yao Chen729093d2017-10-16 10:33:26 -0700138
Yao Chenb7041772017-10-20 16:59:25 -0700139 auto it = mCurrentSlicedCounter.find(eventKey);
Yao Chen729093d2017-10-16 10:33:26 -0700140
141 if (it == mCurrentSlicedCounter.end()) {
142 // create a counter for the new key
Yao Chenb7041772017-10-20 16:59:25 -0700143 mCurrentSlicedCounter[eventKey] = 1;
Yao Chen729093d2017-10-16 10:33:26 -0700144
145 } else {
146 // increment the existing value
147 auto& count = it->second;
148 count++;
149 }
150
Yao Chenb7041772017-10-20 16:59:25 -0700151 VLOG("metric %lld %s->%d", mMetric.metric_id(), eventKey.c_str(),
152 mCurrentSlicedCounter[eventKey]);
Yao Chen44cf27c2017-09-14 22:32:50 -0700153}
154
Yao Chen729093d2017-10-16 10:33:26 -0700155// When a new matched event comes in, we check if event falls into the current
156// bucket. If not, flush the old counter to past buckets and initialize the new bucket.
157void CountMetricProducer::flushCounterIfNeeded(const uint64_t eventTimeNs) {
158 if (mCurrentBucketStartTimeNs + mBucketSizeNs > eventTimeNs) {
Yao Chen44cf27c2017-09-14 22:32:50 -0700159 return;
160 }
161
Yao Chen44cf27c2017-09-14 22:32:50 -0700162 // adjust the bucket start time
Yao Chen729093d2017-10-16 10:33:26 -0700163 int64_t numBucketsForward = (eventTimeNs - mCurrentBucketStartTimeNs) / mBucketSizeNs;
Bookatza4bc9c42017-10-04 11:45:57 -0700164
Yao Chen729093d2017-10-16 10:33:26 -0700165 CountBucketInfo info;
166 info.set_start_bucket_nanos(mCurrentBucketStartTimeNs);
167 info.set_end_bucket_nanos(mCurrentBucketStartTimeNs + mBucketSizeNs);
Bookatza4bc9c42017-10-04 11:45:57 -0700168
Yao Chen729093d2017-10-16 10:33:26 -0700169 for (const auto& counter : mCurrentSlicedCounter) {
170 info.set_count(counter.second);
171 // it will auto create new vector of CountbucketInfo if the key is not found.
172 auto& bucketList = mPastBuckets[counter.first];
173 bucketList.push_back(info);
Yao Chen44cf27c2017-09-14 22:32:50 -0700174
Yao Chen729093d2017-10-16 10:33:26 -0700175 VLOG("metric %lld, dump key value: %s -> %d", mMetric.metric_id(), counter.first.c_str(),
176 counter.second);
177 }
178
179 // Reset counters
180 mCurrentSlicedCounter.clear();
181
182 mCurrentBucketStartTimeNs = mCurrentBucketStartTimeNs + numBucketsForward * mBucketSizeNs;
183 VLOG("metric %lld: new bucket start time: %lld", mMetric.metric_id(),
184 (long long)mCurrentBucketStartTimeNs);
Yao Chen44cf27c2017-09-14 22:32:50 -0700185}
186
187} // namespace statsd
188} // namespace os
Yao Chenb7041772017-10-20 16:59:25 -0700189} // namespace android