blob: d47bd4fe9e44fefa120e3210da78b2dfd0a06ef8 [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
Yao Chen729093d2017-10-16 10:33:26 -070020#include "CountMetricProducer.h"
21#include "stats_util.h"
Yao Chen44cf27c2017-09-14 22:32:50 -070022
Yao Chen44cf27c2017-09-14 22:32:50 -070023#include <limits.h>
24#include <stdlib.h>
25
yrob0378b02017-11-09 20:36:25 -080026using android::util::FIELD_COUNT_REPEATED;
yro2b0f8862017-11-06 14:27:31 -080027using android::util::FIELD_TYPE_BOOL;
28using android::util::FIELD_TYPE_FLOAT;
29using android::util::FIELD_TYPE_INT32;
30using android::util::FIELD_TYPE_INT64;
31using android::util::FIELD_TYPE_MESSAGE;
Yangster-macd1815dc2017-11-13 21:43:15 -080032using android::util::FIELD_TYPE_STRING;
yro24809bd2017-10-31 23:06:53 -070033using android::util::ProtoOutputStream;
Yao Chen729093d2017-10-16 10:33:26 -070034using std::map;
35using std::string;
Yao Chen44cf27c2017-09-14 22:32:50 -070036using std::unordered_map;
Yao Chen729093d2017-10-16 10:33:26 -070037using std::vector;
Yao Chen44cf27c2017-09-14 22:32:50 -070038
39namespace android {
40namespace os {
41namespace statsd {
42
yro24809bd2017-10-31 23:06:53 -070043// for StatsLogReport
Yangster-macd1815dc2017-11-13 21:43:15 -080044const int FIELD_ID_NAME = 1;
yro24809bd2017-10-31 23:06:53 -070045const int FIELD_ID_START_REPORT_NANOS = 2;
46const int FIELD_ID_END_REPORT_NANOS = 3;
47const int FIELD_ID_COUNT_METRICS = 5;
48// for CountMetricDataWrapper
49const int FIELD_ID_DATA = 1;
50// for CountMetricData
51const int FIELD_ID_DIMENSION = 1;
52const int FIELD_ID_BUCKET_INFO = 2;
53// for KeyValuePair
54const int FIELD_ID_KEY = 1;
55const int FIELD_ID_VALUE_STR = 2;
56const int FIELD_ID_VALUE_INT = 3;
57const int FIELD_ID_VALUE_BOOL = 4;
58const int FIELD_ID_VALUE_FLOAT = 5;
59// for CountBucketInfo
60const int FIELD_ID_START_BUCKET_NANOS = 1;
61const int FIELD_ID_END_BUCKET_NANOS = 2;
62const int FIELD_ID_COUNT = 3;
63
Yao Chen729093d2017-10-16 10:33:26 -070064// TODO: add back AnomalyTracker.
Yang Lu3eba6212017-10-25 19:54:45 -070065
Yao Chen729093d2017-10-16 10:33:26 -070066CountMetricProducer::CountMetricProducer(const CountMetric& metric, const int conditionIndex,
Yao Chen93fe3a32017-11-02 13:52:59 -070067 const sp<ConditionWizard>& wizard,
68 const uint64_t startTimeNs)
69 : MetricProducer(startTimeNs, conditionIndex, wizard), mMetric(metric) {
Yao Chen44cf27c2017-09-14 22:32:50 -070070 // TODO: evaluate initial conditions. and set mConditionMet.
71 if (metric.has_bucket() && metric.bucket().has_bucket_size_millis()) {
Yao Chen729093d2017-10-16 10:33:26 -070072 mBucketSizeNs = metric.bucket().bucket_size_millis() * 1000 * 1000;
Yao Chen44cf27c2017-09-14 22:32:50 -070073 } else {
Yao Chen729093d2017-10-16 10:33:26 -070074 mBucketSizeNs = LLONG_MAX;
Yao Chen44cf27c2017-09-14 22:32:50 -070075 }
76
Yao Chen729093d2017-10-16 10:33:26 -070077 // TODO: use UidMap if uid->pkg_name is required
78 mDimension.insert(mDimension.begin(), metric.dimension().begin(), metric.dimension().end());
79
80 if (metric.links().size() > 0) {
81 mConditionLinks.insert(mConditionLinks.begin(), metric.links().begin(),
82 metric.links().end());
83 mConditionSliced = true;
84 }
85
yro24809bd2017-10-31 23:06:53 -070086 startNewProtoOutputStream(mStartTimeNs);
87
Yangster-macd1815dc2017-11-13 21:43:15 -080088 VLOG("metric %s created. bucket size %lld start_time: %lld", metric.name().c_str(),
Yao Chen729093d2017-10-16 10:33:26 -070089 (long long)mBucketSizeNs, (long long)mStartTimeNs);
Yao Chen44cf27c2017-09-14 22:32:50 -070090}
91
Yao Chen44cf27c2017-09-14 22:32:50 -070092CountMetricProducer::~CountMetricProducer() {
93 VLOG("~CountMetricProducer() called");
94}
95
yro24809bd2017-10-31 23:06:53 -070096void CountMetricProducer::startNewProtoOutputStream(long long startTime) {
97 mProto = std::make_unique<ProtoOutputStream>();
Yangster-macd1815dc2017-11-13 21:43:15 -080098 mProto->write(FIELD_TYPE_STRING | FIELD_ID_NAME, mMetric.name());
yro24809bd2017-10-31 23:06:53 -070099 mProto->write(FIELD_TYPE_INT64 | FIELD_ID_START_REPORT_NANOS, startTime);
100 mProtoToken = mProto->start(FIELD_TYPE_MESSAGE | FIELD_ID_COUNT_METRICS);
Yao Chen44cf27c2017-09-14 22:32:50 -0700101}
102
yro24809bd2017-10-31 23:06:53 -0700103void CountMetricProducer::finish() {
Yao Chen729093d2017-10-16 10:33:26 -0700104}
105
Yao Chen5154a372017-10-30 22:57:06 -0700106void CountMetricProducer::onSlicedConditionMayChange(const uint64_t eventTime) {
Yangster-macd1815dc2017-11-13 21:43:15 -0800107 VLOG("Metric %s onSlicedConditionMayChange", mMetric.name().c_str());
Yao Chen729093d2017-10-16 10:33:26 -0700108}
109
yro17adac92017-11-08 23:16:29 -0800110std::unique_ptr<std::vector<uint8_t>> CountMetricProducer::onDumpReport() {
Yao Chen93fe3a32017-11-02 13:52:59 -0700111 long long endTime = time(nullptr) * NS_PER_SEC;
Yao Chen729093d2017-10-16 10:33:26 -0700112
113 // Dump current bucket if it's stale.
114 // If current bucket is still on-going, don't force dump current bucket.
115 // In finish(), We can force dump current bucket.
Yangster-mace2cd6d52017-11-09 20:38:30 -0800116 flushIfNeeded(endTime);
Yangster-macd1815dc2017-11-13 21:43:15 -0800117 VLOG("metric %s dump report now...", mMetric.name().c_str());
Yao Chen729093d2017-10-16 10:33:26 -0700118
Yao Chen93fe3a32017-11-02 13:52:59 -0700119 for (const auto& counter : mPastBuckets) {
yro24809bd2017-10-31 23:06:53 -0700120 const HashableDimensionKey& hashableKey = counter.first;
Yao Chen93fe3a32017-11-02 13:52:59 -0700121 VLOG(" dimension key %s", hashableKey.c_str());
Yao Chen729093d2017-10-16 10:33:26 -0700122 auto it = mDimensionKeyMap.find(hashableKey);
123 if (it == mDimensionKeyMap.end()) {
124 ALOGE("Dimension key %s not found?!?! skip...", hashableKey.c_str());
125 continue;
126 }
yrob0378b02017-11-09 20:36:25 -0800127 long long wrapperToken =
128 mProto->start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | FIELD_ID_DATA);
Yao Chen729093d2017-10-16 10:33:26 -0700129
yro24809bd2017-10-31 23:06:53 -0700130 // First fill dimension (KeyValuePairs).
131 for (const auto& kv : it->second) {
yrob0378b02017-11-09 20:36:25 -0800132 long long dimensionToken =
133 mProto->start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | FIELD_ID_DIMENSION);
yro24809bd2017-10-31 23:06:53 -0700134 mProto->write(FIELD_TYPE_INT32 | FIELD_ID_KEY, kv.key());
135 if (kv.has_value_str()) {
136 mProto->write(FIELD_TYPE_INT32 | FIELD_ID_VALUE_STR, kv.value_str());
137 } else if (kv.has_value_int()) {
138 mProto->write(FIELD_TYPE_INT64 | FIELD_ID_VALUE_INT, kv.value_int());
139 } else if (kv.has_value_bool()) {
140 mProto->write(FIELD_TYPE_BOOL | FIELD_ID_VALUE_BOOL, kv.value_bool());
141 } else if (kv.has_value_float()) {
142 mProto->write(FIELD_TYPE_FLOAT | FIELD_ID_VALUE_FLOAT, kv.value_float());
143 }
144 mProto->end(dimensionToken);
145 }
146
147 // Then fill bucket_info (CountBucketInfo).
Yao Chen93fe3a32017-11-02 13:52:59 -0700148 for (const auto& bucket : counter.second) {
yrob0378b02017-11-09 20:36:25 -0800149 long long bucketInfoToken =
150 mProto->start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | FIELD_ID_BUCKET_INFO);
Yao Chen93fe3a32017-11-02 13:52:59 -0700151 mProto->write(FIELD_TYPE_INT64 | FIELD_ID_START_BUCKET_NANOS,
152 (long long)bucket.mBucketStartNs);
153 mProto->write(FIELD_TYPE_INT64 | FIELD_ID_END_BUCKET_NANOS,
154 (long long)bucket.mBucketEndNs);
155 mProto->write(FIELD_TYPE_INT64 | FIELD_ID_COUNT, (long long)bucket.mCount);
156 mProto->end(bucketInfoToken);
157 VLOG("\t bucket [%lld - %lld] count: %lld", (long long)bucket.mBucketStartNs,
158 (long long)bucket.mBucketEndNs, (long long)bucket.mCount);
yro24809bd2017-10-31 23:06:53 -0700159 }
yro24809bd2017-10-31 23:06:53 -0700160 mProto->end(wrapperToken);
Yao Chen729093d2017-10-16 10:33:26 -0700161 }
yro24809bd2017-10-31 23:06:53 -0700162
163 mProto->end(mProtoToken);
164 mProto->write(FIELD_TYPE_INT64 | FIELD_ID_END_REPORT_NANOS,
165 (long long)mCurrentBucketStartTimeNs);
166
Yangster-macd1815dc2017-11-13 21:43:15 -0800167 VLOG("metric %s dump report now...", mMetric.name().c_str());
yro17adac92017-11-08 23:16:29 -0800168 std::unique_ptr<std::vector<uint8_t>> buffer = serializeProto();
yro24809bd2017-10-31 23:06:53 -0700169
170 startNewProtoOutputStream(endTime);
Yao Chen93fe3a32017-11-02 13:52:59 -0700171 mPastBuckets.clear();
yro24809bd2017-10-31 23:06:53 -0700172
yro17adac92017-11-08 23:16:29 -0800173 return buffer;
yro24809bd2017-10-31 23:06:53 -0700174
175 // TODO: Clear mDimensionKeyMap once the report is dumped.
Yao Chen44cf27c2017-09-14 22:32:50 -0700176}
177
Yao Chen5154a372017-10-30 22:57:06 -0700178void CountMetricProducer::onConditionChanged(const bool conditionMet, const uint64_t eventTime) {
Yangster-macd1815dc2017-11-13 21:43:15 -0800179 VLOG("Metric %s onConditionChanged", mMetric.name().c_str());
Yao Chencaf339d2017-10-06 16:01:10 -0700180 mCondition = conditionMet;
181}
182
Yao Chenb7041772017-10-20 16:59:25 -0700183void CountMetricProducer::onMatchedLogEventInternal(
184 const size_t matcherIndex, const HashableDimensionKey& eventKey,
185 const map<string, HashableDimensionKey>& conditionKey, bool condition,
Chenjie Yub3dda412017-10-24 13:41:59 -0700186 const LogEvent& event, bool scheduledPull) {
Yao Chen729093d2017-10-16 10:33:26 -0700187 uint64_t eventTimeNs = event.GetTimestampNs();
Yao Chen44cf27c2017-09-14 22:32:50 -0700188
Yangster-mace2cd6d52017-11-09 20:38:30 -0800189 flushIfNeeded(eventTimeNs);
Yao Chen729093d2017-10-16 10:33:26 -0700190
Yao Chenb7041772017-10-20 16:59:25 -0700191 if (condition == false) {
192 return;
Yao Chen44cf27c2017-09-14 22:32:50 -0700193 }
Yao Chen729093d2017-10-16 10:33:26 -0700194
Yang Lu3eba6212017-10-25 19:54:45 -0700195 auto it = mCurrentSlicedCounter->find(eventKey);
Yao Chen729093d2017-10-16 10:33:26 -0700196
Yang Lu3eba6212017-10-25 19:54:45 -0700197 if (it == mCurrentSlicedCounter->end()) {
Yao Chen729093d2017-10-16 10:33:26 -0700198 // create a counter for the new key
Yang Lu3eba6212017-10-25 19:54:45 -0700199 (*mCurrentSlicedCounter)[eventKey] = 1;
Yao Chen729093d2017-10-16 10:33:26 -0700200 } else {
201 // increment the existing value
202 auto& count = it->second;
203 count++;
204 }
205
Yangster-mace2cd6d52017-11-09 20:38:30 -0800206 for (auto& tracker : mAnomalyTrackers) {
207 tracker->detectAndDeclareAnomaly(eventTimeNs, mCurrentBucketNum, eventKey,
208 mCurrentSlicedCounter->find(eventKey)->second);
209 }
210
211 VLOG("metric %s %s->%lld", mMetric.name().c_str(), eventKey.c_str(),
212 (long long)(*mCurrentSlicedCounter)[eventKey]);
Yao Chen44cf27c2017-09-14 22:32:50 -0700213}
214
Yao Chen729093d2017-10-16 10:33:26 -0700215// When a new matched event comes in, we check if event falls into the current
216// bucket. If not, flush the old counter to past buckets and initialize the new bucket.
Yangster-mace2cd6d52017-11-09 20:38:30 -0800217void CountMetricProducer::flushIfNeeded(const uint64_t eventTimeNs) {
218 if (eventTimeNs < mCurrentBucketStartTimeNs + mBucketSizeNs) {
Yao Chen44cf27c2017-09-14 22:32:50 -0700219 return;
220 }
221
Yao Chen93fe3a32017-11-02 13:52:59 -0700222 CountBucket info;
223 info.mBucketStartNs = mCurrentBucketStartTimeNs;
224 info.mBucketEndNs = mCurrentBucketStartTimeNs + mBucketSizeNs;
Yangster-mace2cd6d52017-11-09 20:38:30 -0800225 info.mBucketNum = mCurrentBucketNum;
Yang Lu3eba6212017-10-25 19:54:45 -0700226 for (const auto& counter : *mCurrentSlicedCounter) {
Yao Chen93fe3a32017-11-02 13:52:59 -0700227 info.mCount = counter.second;
228 auto& bucketList = mPastBuckets[counter.first];
229 bucketList.push_back(info);
Yangster-mace2cd6d52017-11-09 20:38:30 -0800230 VLOG("metric %s, dump key value: %s -> %lld", mMetric.name().c_str(), counter.first.c_str(),
231 (long long)counter.second);
Yao Chen729093d2017-10-16 10:33:26 -0700232 }
233
Yang Lu3eba6212017-10-25 19:54:45 -0700234 for (auto& tracker : mAnomalyTrackers) {
Yangster-mace2cd6d52017-11-09 20:38:30 -0800235 tracker->addPastBucket(mCurrentSlicedCounter, mCurrentBucketNum);
Yang Lu3eba6212017-10-25 19:54:45 -0700236 }
Bookatzd3606c72017-10-19 10:13:49 -0700237
Yang Lu3eba6212017-10-25 19:54:45 -0700238 // Reset counters (do not clear, since the old one is still referenced in mAnomalyTrackers).
239 mCurrentSlicedCounter = std::make_shared<DimToValMap>();
Yangster-mace2cd6d52017-11-09 20:38:30 -0800240 uint64_t numBucketsForward = (eventTimeNs - mCurrentBucketStartTimeNs) / mBucketSizeNs;
Yao Chen729093d2017-10-16 10:33:26 -0700241 mCurrentBucketStartTimeNs = mCurrentBucketStartTimeNs + numBucketsForward * mBucketSizeNs;
Yang Lu3eba6212017-10-25 19:54:45 -0700242 mCurrentBucketNum += numBucketsForward;
Yangster-macd1815dc2017-11-13 21:43:15 -0800243 VLOG("metric %s: new bucket start time: %lld", mMetric.name().c_str(),
Yao Chen729093d2017-10-16 10:33:26 -0700244 (long long)mCurrentBucketStartTimeNs);
Yao Chen44cf27c2017-09-14 22:32:50 -0700245}
246
yro24809bd2017-10-31 23:06:53 -0700247// Rough estimate of CountMetricProducer buffer stored. This number will be
248// greater than actual data size as it contains each dimension of
249// CountMetricData is duplicated.
yro69007c82017-10-26 20:42:57 -0700250size_t CountMetricProducer::byteSize() {
Yangster-mace2cd6d52017-11-09 20:38:30 -0800251 size_t totalSize = 0;
252 for (const auto& pair : mPastBuckets) {
253 totalSize += pair.second.size() * kBucketSize;
254 }
255 return totalSize;
yro69007c82017-10-26 20:42:57 -0700256}
257
Yao Chen44cf27c2017-09-14 22:32:50 -0700258} // namespace statsd
259} // namespace os
yro69007c82017-10-26 20:42:57 -0700260} // namespace android