blob: 69f336f420fcc35c30b458f9a333d58a88b858b8 [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),
Bookatzd3606c72017-10-19 10:13:49 -070042 mMetric(metric) {
Yao Chen44cf27c2017-09-14 22:32:50 -070043 // TODO: evaluate initial conditions. and set mConditionMet.
44 if (metric.has_bucket() && metric.bucket().has_bucket_size_millis()) {
Yao Chen729093d2017-10-16 10:33:26 -070045 mBucketSizeNs = metric.bucket().bucket_size_millis() * 1000 * 1000;
Yao Chen44cf27c2017-09-14 22:32:50 -070046 } else {
Yao Chen729093d2017-10-16 10:33:26 -070047 mBucketSizeNs = LLONG_MAX;
Yao Chen44cf27c2017-09-14 22:32:50 -070048 }
49
Bookatzd3606c72017-10-19 10:13:49 -070050 mAnomalyTrackers.reserve(metric.alerts_size());
51 for (int i = 0; i < metric.alerts_size(); i++) {
52 const Alert& alert = metric.alerts(i);
53 if (alert.trigger_if_sum_gt() > 0 && alert.number_of_buckets() > 0) {
54 mAnomalyTrackers.push_back(std::make_unique<CountAnomalyTracker>(alert));
55 } else {
56 ALOGW("Ignoring invalid count metric alert: threshold=%lld num_buckets= %d",
57 alert.trigger_if_sum_gt(), alert.number_of_buckets());
58 }
59 }
60
Yao Chen729093d2017-10-16 10:33:26 -070061 // TODO: use UidMap if uid->pkg_name is required
62 mDimension.insert(mDimension.begin(), metric.dimension().begin(), metric.dimension().end());
63
64 if (metric.links().size() > 0) {
65 mConditionLinks.insert(mConditionLinks.begin(), metric.links().begin(),
66 metric.links().end());
67 mConditionSliced = true;
68 }
69
70 VLOG("metric %lld created. bucket size %lld start_time: %lld", metric.metric_id(),
71 (long long)mBucketSizeNs, (long long)mStartTimeNs);
Yao Chen44cf27c2017-09-14 22:32:50 -070072}
73
Yao Chen44cf27c2017-09-14 22:32:50 -070074CountMetricProducer::~CountMetricProducer() {
75 VLOG("~CountMetricProducer() called");
76}
77
78void CountMetricProducer::finish() {
79 // TODO: write the StatsLogReport to dropbox using
80 // DropboxWriter.
Yao Chen44cf27c2017-09-14 22:32:50 -070081}
82
Yao Chen729093d2017-10-16 10:33:26 -070083static void addSlicedCounterToReport(StatsLogReport_CountMetricDataWrapper& wrapper,
84 const vector<KeyValuePair>& key,
85 const vector<CountBucketInfo>& buckets) {
86 CountMetricData* data = wrapper.add_data();
87 for (const auto& kv : key) {
88 data->add_dimension()->CopyFrom(kv);
89 }
90 for (const auto& bucket : buckets) {
91 data->add_bucket_info()->CopyFrom(bucket);
92 VLOG("\t bucket [%lld - %lld] count: %lld", bucket.start_bucket_nanos(),
93 bucket.end_bucket_nanos(), bucket.count());
94 }
95}
96
97void CountMetricProducer::onSlicedConditionMayChange() {
98 VLOG("Metric %lld onSlicedConditionMayChange", mMetric.metric_id());
99}
100
101StatsLogReport CountMetricProducer::onDumpReport() {
102 VLOG("metric %lld dump report now...", mMetric.metric_id());
103
104 StatsLogReport report;
105 report.set_metric_id(mMetric.metric_id());
106 report.set_start_report_nanos(mStartTimeNs);
107
108 // Dump current bucket if it's stale.
109 // If current bucket is still on-going, don't force dump current bucket.
110 // In finish(), We can force dump current bucket.
111 flushCounterIfNeeded(time(nullptr) * NANO_SECONDS_IN_A_SECOND);
112 report.set_end_report_nanos(mCurrentBucketStartTimeNs);
113
114 StatsLogReport_CountMetricDataWrapper* wrapper = report.mutable_count_metrics();
115
116 for (const auto& pair : mPastBuckets) {
117 const HashableDimensionKey& hashableKey = pair.first;
118 auto it = mDimensionKeyMap.find(hashableKey);
119 if (it == mDimensionKeyMap.end()) {
120 ALOGE("Dimension key %s not found?!?! skip...", hashableKey.c_str());
121 continue;
122 }
123
124 VLOG(" dimension key %s", hashableKey.c_str());
125 addSlicedCounterToReport(*wrapper, it->second, pair.second);
126 }
127 return report;
128 // TODO: Clear mPastBuckets, mDimensionKeyMap once the report is dumped.
Yao Chen44cf27c2017-09-14 22:32:50 -0700129}
130
Yao Chencaf339d2017-10-06 16:01:10 -0700131void CountMetricProducer::onConditionChanged(const bool conditionMet) {
Yao Chen729093d2017-10-16 10:33:26 -0700132 VLOG("Metric %lld onConditionChanged", mMetric.metric_id());
Yao Chencaf339d2017-10-06 16:01:10 -0700133 mCondition = conditionMet;
134}
135
Yao Chenb7041772017-10-20 16:59:25 -0700136void CountMetricProducer::onMatchedLogEventInternal(
137 const size_t matcherIndex, const HashableDimensionKey& eventKey,
138 const map<string, HashableDimensionKey>& conditionKey, bool condition,
139 const LogEvent& event) {
Yao Chen729093d2017-10-16 10:33:26 -0700140 uint64_t eventTimeNs = event.GetTimestampNs();
Yao Chen44cf27c2017-09-14 22:32:50 -0700141
Yao Chen729093d2017-10-16 10:33:26 -0700142 flushCounterIfNeeded(eventTimeNs);
143
Yao Chenb7041772017-10-20 16:59:25 -0700144 if (condition == false) {
145 return;
Yao Chen44cf27c2017-09-14 22:32:50 -0700146 }
Yao Chen729093d2017-10-16 10:33:26 -0700147
Yao Chenb7041772017-10-20 16:59:25 -0700148 auto it = mCurrentSlicedCounter.find(eventKey);
Yao Chen729093d2017-10-16 10:33:26 -0700149
150 if (it == mCurrentSlicedCounter.end()) {
151 // create a counter for the new key
Yao Chenb7041772017-10-20 16:59:25 -0700152 mCurrentSlicedCounter[eventKey] = 1;
Yao Chen729093d2017-10-16 10:33:26 -0700153
154 } else {
155 // increment the existing value
156 auto& count = it->second;
157 count++;
158 }
159
Bookatzd3606c72017-10-19 10:13:49 -0700160 // TODO: Re-add anomaly detection (similar to):
161 // for (auto& tracker : mAnomalyTrackers) {
162 // tracker->checkAnomaly(mCounter);
163 // }
164
Yao Chenb7041772017-10-20 16:59:25 -0700165 VLOG("metric %lld %s->%d", mMetric.metric_id(), eventKey.c_str(),
166 mCurrentSlicedCounter[eventKey]);
Yao Chen44cf27c2017-09-14 22:32:50 -0700167}
168
Yao Chen729093d2017-10-16 10:33:26 -0700169// When a new matched event comes in, we check if event falls into the current
170// bucket. If not, flush the old counter to past buckets and initialize the new bucket.
171void CountMetricProducer::flushCounterIfNeeded(const uint64_t eventTimeNs) {
172 if (mCurrentBucketStartTimeNs + mBucketSizeNs > eventTimeNs) {
Yao Chen44cf27c2017-09-14 22:32:50 -0700173 return;
174 }
175
Yao Chen44cf27c2017-09-14 22:32:50 -0700176 // adjust the bucket start time
Yao Chen729093d2017-10-16 10:33:26 -0700177 int64_t numBucketsForward = (eventTimeNs - mCurrentBucketStartTimeNs) / mBucketSizeNs;
Bookatza4bc9c42017-10-04 11:45:57 -0700178
Yao Chen729093d2017-10-16 10:33:26 -0700179 CountBucketInfo info;
180 info.set_start_bucket_nanos(mCurrentBucketStartTimeNs);
181 info.set_end_bucket_nanos(mCurrentBucketStartTimeNs + mBucketSizeNs);
Bookatza4bc9c42017-10-04 11:45:57 -0700182
Yao Chen729093d2017-10-16 10:33:26 -0700183 for (const auto& counter : mCurrentSlicedCounter) {
184 info.set_count(counter.second);
185 // it will auto create new vector of CountbucketInfo if the key is not found.
186 auto& bucketList = mPastBuckets[counter.first];
187 bucketList.push_back(info);
Yao Chen44cf27c2017-09-14 22:32:50 -0700188
Yao Chen729093d2017-10-16 10:33:26 -0700189 VLOG("metric %lld, dump key value: %s -> %d", mMetric.metric_id(), counter.first.c_str(),
190 counter.second);
191 }
192
Bookatzd3606c72017-10-19 10:13:49 -0700193 // TODO: Re-add anomaly detection (similar to):
194 // for (auto& tracker : mAnomalyTrackers) {
195 // tracker->addPastBucket(mCounter, numBucketsForward);
196 //}
197
Yao Chen729093d2017-10-16 10:33:26 -0700198 // Reset counters
199 mCurrentSlicedCounter.clear();
200
201 mCurrentBucketStartTimeNs = mCurrentBucketStartTimeNs + numBucketsForward * mBucketSizeNs;
202 VLOG("metric %lld: new bucket start time: %lld", mMetric.metric_id(),
203 (long long)mCurrentBucketStartTimeNs);
Yao Chen44cf27c2017-09-14 22:32:50 -0700204}
205
yro69007c82017-10-26 20:42:57 -0700206size_t CountMetricProducer::byteSize() {
207// TODO: return actual proto size when ProtoOutputStream is ready for use for
208// CountMetricsProducer.
209// return mProto->size();
210 return 0;
211}
212
Yao Chen44cf27c2017-09-14 22:32:50 -0700213} // namespace statsd
214} // namespace os
yro69007c82017-10-26 20:42:57 -0700215} // namespace android