blob: f9da68e8e5c5224047fac1caa4af55aa1ece1696 [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
Yang Lu3eba6212017-10-25 19:54:45 -070020#include "../anomaly/DiscreteAnomalyTracker.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
Yao Chen44cf27c2017-09-14 22:32:50 -070024#include <limits.h>
25#include <stdlib.h>
26
yrob0378b02017-11-09 20:36:25 -080027using android::util::FIELD_COUNT_REPEATED;
yro2b0f8862017-11-06 14:27:31 -080028using android::util::FIELD_TYPE_BOOL;
29using android::util::FIELD_TYPE_FLOAT;
30using android::util::FIELD_TYPE_INT32;
31using android::util::FIELD_TYPE_INT64;
32using android::util::FIELD_TYPE_MESSAGE;
Yangster-macd1815dc2017-11-13 21:43:15 -080033using android::util::FIELD_TYPE_STRING;
yro24809bd2017-10-31 23:06:53 -070034using android::util::ProtoOutputStream;
Yao Chen729093d2017-10-16 10:33:26 -070035using std::map;
36using std::string;
Yao Chen44cf27c2017-09-14 22:32:50 -070037using std::unordered_map;
Yao Chen729093d2017-10-16 10:33:26 -070038using std::vector;
Yao Chen44cf27c2017-09-14 22:32:50 -070039
40namespace android {
41namespace os {
42namespace statsd {
43
yro24809bd2017-10-31 23:06:53 -070044// for StatsLogReport
Yangster-macd1815dc2017-11-13 21:43:15 -080045const int FIELD_ID_NAME = 1;
yro24809bd2017-10-31 23:06:53 -070046const int FIELD_ID_START_REPORT_NANOS = 2;
47const int FIELD_ID_END_REPORT_NANOS = 3;
48const int FIELD_ID_COUNT_METRICS = 5;
49// for CountMetricDataWrapper
50const int FIELD_ID_DATA = 1;
51// for CountMetricData
52const int FIELD_ID_DIMENSION = 1;
53const int FIELD_ID_BUCKET_INFO = 2;
54// for KeyValuePair
55const int FIELD_ID_KEY = 1;
56const int FIELD_ID_VALUE_STR = 2;
57const int FIELD_ID_VALUE_INT = 3;
58const int FIELD_ID_VALUE_BOOL = 4;
59const int FIELD_ID_VALUE_FLOAT = 5;
60// for CountBucketInfo
61const int FIELD_ID_START_BUCKET_NANOS = 1;
62const int FIELD_ID_END_BUCKET_NANOS = 2;
63const int FIELD_ID_COUNT = 3;
64
Yao Chen729093d2017-10-16 10:33:26 -070065// TODO: add back AnomalyTracker.
Yang Lu3eba6212017-10-25 19:54:45 -070066
Yao Chen729093d2017-10-16 10:33:26 -070067CountMetricProducer::CountMetricProducer(const CountMetric& metric, const int conditionIndex,
Yao Chen93fe3a32017-11-02 13:52:59 -070068 const sp<ConditionWizard>& wizard,
69 const uint64_t startTimeNs)
70 : MetricProducer(startTimeNs, conditionIndex, wizard), mMetric(metric) {
Yao Chen44cf27c2017-09-14 22:32:50 -070071 // TODO: evaluate initial conditions. and set mConditionMet.
72 if (metric.has_bucket() && metric.bucket().has_bucket_size_millis()) {
Yao Chen729093d2017-10-16 10:33:26 -070073 mBucketSizeNs = metric.bucket().bucket_size_millis() * 1000 * 1000;
Yao Chen44cf27c2017-09-14 22:32:50 -070074 } else {
Yao Chen729093d2017-10-16 10:33:26 -070075 mBucketSizeNs = LLONG_MAX;
Yao Chen44cf27c2017-09-14 22:32:50 -070076 }
77
Yao Chen729093d2017-10-16 10:33:26 -070078 // TODO: use UidMap if uid->pkg_name is required
79 mDimension.insert(mDimension.begin(), metric.dimension().begin(), metric.dimension().end());
80
81 if (metric.links().size() > 0) {
82 mConditionLinks.insert(mConditionLinks.begin(), metric.links().begin(),
83 metric.links().end());
84 mConditionSliced = true;
85 }
86
yro24809bd2017-10-31 23:06:53 -070087 startNewProtoOutputStream(mStartTimeNs);
88
Yangster-macd1815dc2017-11-13 21:43:15 -080089 VLOG("metric %s created. bucket size %lld start_time: %lld", metric.name().c_str(),
Yao Chen729093d2017-10-16 10:33:26 -070090 (long long)mBucketSizeNs, (long long)mStartTimeNs);
Yao Chen44cf27c2017-09-14 22:32:50 -070091}
92
Yao Chen44cf27c2017-09-14 22:32:50 -070093CountMetricProducer::~CountMetricProducer() {
94 VLOG("~CountMetricProducer() called");
95}
96
yro24809bd2017-10-31 23:06:53 -070097void CountMetricProducer::startNewProtoOutputStream(long long startTime) {
98 mProto = std::make_unique<ProtoOutputStream>();
Yangster-macd1815dc2017-11-13 21:43:15 -080099 mProto->write(FIELD_TYPE_STRING | FIELD_ID_NAME, mMetric.name());
yro24809bd2017-10-31 23:06:53 -0700100 mProto->write(FIELD_TYPE_INT64 | FIELD_ID_START_REPORT_NANOS, startTime);
101 mProtoToken = mProto->start(FIELD_TYPE_MESSAGE | FIELD_ID_COUNT_METRICS);
Yao Chen44cf27c2017-09-14 22:32:50 -0700102}
103
yro24809bd2017-10-31 23:06:53 -0700104void CountMetricProducer::finish() {
Yao Chen729093d2017-10-16 10:33:26 -0700105}
106
Yao Chen5154a372017-10-30 22:57:06 -0700107void CountMetricProducer::onSlicedConditionMayChange(const uint64_t eventTime) {
Yangster-macd1815dc2017-11-13 21:43:15 -0800108 VLOG("Metric %s onSlicedConditionMayChange", mMetric.name().c_str());
Yao Chen729093d2017-10-16 10:33:26 -0700109}
110
yro17adac92017-11-08 23:16:29 -0800111std::unique_ptr<std::vector<uint8_t>> CountMetricProducer::onDumpReport() {
Yao Chen93fe3a32017-11-02 13:52:59 -0700112 long long endTime = time(nullptr) * NS_PER_SEC;
Yao Chen729093d2017-10-16 10:33:26 -0700113
114 // Dump current bucket if it's stale.
115 // If current bucket is still on-going, don't force dump current bucket.
116 // In finish(), We can force dump current bucket.
yro24809bd2017-10-31 23:06:53 -0700117 flushCounterIfNeeded(endTime);
Yangster-macd1815dc2017-11-13 21:43:15 -0800118 VLOG("metric %s dump report now...", mMetric.name().c_str());
Yao Chen729093d2017-10-16 10:33:26 -0700119
Yao Chen93fe3a32017-11-02 13:52:59 -0700120 for (const auto& counter : mPastBuckets) {
yro24809bd2017-10-31 23:06:53 -0700121 const HashableDimensionKey& hashableKey = counter.first;
Yao Chen93fe3a32017-11-02 13:52:59 -0700122 VLOG(" dimension key %s", hashableKey.c_str());
Yao Chen729093d2017-10-16 10:33:26 -0700123 auto it = mDimensionKeyMap.find(hashableKey);
124 if (it == mDimensionKeyMap.end()) {
125 ALOGE("Dimension key %s not found?!?! skip...", hashableKey.c_str());
126 continue;
127 }
yrob0378b02017-11-09 20:36:25 -0800128 long long wrapperToken =
129 mProto->start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | FIELD_ID_DATA);
Yao Chen729093d2017-10-16 10:33:26 -0700130
yro24809bd2017-10-31 23:06:53 -0700131 // First fill dimension (KeyValuePairs).
132 for (const auto& kv : it->second) {
yrob0378b02017-11-09 20:36:25 -0800133 long long dimensionToken =
134 mProto->start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | FIELD_ID_DIMENSION);
yro24809bd2017-10-31 23:06:53 -0700135 mProto->write(FIELD_TYPE_INT32 | FIELD_ID_KEY, kv.key());
136 if (kv.has_value_str()) {
137 mProto->write(FIELD_TYPE_INT32 | FIELD_ID_VALUE_STR, kv.value_str());
138 } else if (kv.has_value_int()) {
139 mProto->write(FIELD_TYPE_INT64 | FIELD_ID_VALUE_INT, kv.value_int());
140 } else if (kv.has_value_bool()) {
141 mProto->write(FIELD_TYPE_BOOL | FIELD_ID_VALUE_BOOL, kv.value_bool());
142 } else if (kv.has_value_float()) {
143 mProto->write(FIELD_TYPE_FLOAT | FIELD_ID_VALUE_FLOAT, kv.value_float());
144 }
145 mProto->end(dimensionToken);
146 }
147
148 // Then fill bucket_info (CountBucketInfo).
Yao Chen93fe3a32017-11-02 13:52:59 -0700149 for (const auto& bucket : counter.second) {
yrob0378b02017-11-09 20:36:25 -0800150 long long bucketInfoToken =
151 mProto->start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | FIELD_ID_BUCKET_INFO);
Yao Chen93fe3a32017-11-02 13:52:59 -0700152 mProto->write(FIELD_TYPE_INT64 | FIELD_ID_START_BUCKET_NANOS,
153 (long long)bucket.mBucketStartNs);
154 mProto->write(FIELD_TYPE_INT64 | FIELD_ID_END_BUCKET_NANOS,
155 (long long)bucket.mBucketEndNs);
156 mProto->write(FIELD_TYPE_INT64 | FIELD_ID_COUNT, (long long)bucket.mCount);
157 mProto->end(bucketInfoToken);
158 VLOG("\t bucket [%lld - %lld] count: %lld", (long long)bucket.mBucketStartNs,
159 (long long)bucket.mBucketEndNs, (long long)bucket.mCount);
yro24809bd2017-10-31 23:06:53 -0700160 }
yro24809bd2017-10-31 23:06:53 -0700161 mProto->end(wrapperToken);
Yao Chen729093d2017-10-16 10:33:26 -0700162 }
yro24809bd2017-10-31 23:06:53 -0700163
164 mProto->end(mProtoToken);
165 mProto->write(FIELD_TYPE_INT64 | FIELD_ID_END_REPORT_NANOS,
166 (long long)mCurrentBucketStartTimeNs);
167
Yangster-macd1815dc2017-11-13 21:43:15 -0800168 VLOG("metric %s dump report now...", mMetric.name().c_str());
yro17adac92017-11-08 23:16:29 -0800169 std::unique_ptr<std::vector<uint8_t>> buffer = serializeProto();
yro24809bd2017-10-31 23:06:53 -0700170
171 startNewProtoOutputStream(endTime);
Yao Chen93fe3a32017-11-02 13:52:59 -0700172 mPastBuckets.clear();
yro24809bd2017-10-31 23:06:53 -0700173 mByteSize = 0;
174
yro17adac92017-11-08 23:16:29 -0800175 return buffer;
yro24809bd2017-10-31 23:06:53 -0700176
177 // TODO: Clear mDimensionKeyMap once the report is dumped.
Yao Chen44cf27c2017-09-14 22:32:50 -0700178}
179
Yao Chen5154a372017-10-30 22:57:06 -0700180void CountMetricProducer::onConditionChanged(const bool conditionMet, const uint64_t eventTime) {
Yangster-macd1815dc2017-11-13 21:43:15 -0800181 VLOG("Metric %s onConditionChanged", mMetric.name().c_str());
Yao Chencaf339d2017-10-06 16:01:10 -0700182 mCondition = conditionMet;
183}
184
Yao Chenb7041772017-10-20 16:59:25 -0700185void CountMetricProducer::onMatchedLogEventInternal(
186 const size_t matcherIndex, const HashableDimensionKey& eventKey,
187 const map<string, HashableDimensionKey>& conditionKey, bool condition,
Chenjie Yub3dda412017-10-24 13:41:59 -0700188 const LogEvent& event, bool scheduledPull) {
Yao Chen729093d2017-10-16 10:33:26 -0700189 uint64_t eventTimeNs = event.GetTimestampNs();
Yao Chen44cf27c2017-09-14 22:32:50 -0700190
Yao Chen729093d2017-10-16 10:33:26 -0700191 flushCounterIfNeeded(eventTimeNs);
192
Yao Chenb7041772017-10-20 16:59:25 -0700193 if (condition == false) {
194 return;
Yao Chen44cf27c2017-09-14 22:32:50 -0700195 }
Yao Chen729093d2017-10-16 10:33:26 -0700196
Yang Lu3eba6212017-10-25 19:54:45 -0700197 auto it = mCurrentSlicedCounter->find(eventKey);
Yao Chen729093d2017-10-16 10:33:26 -0700198
Yang Lu3eba6212017-10-25 19:54:45 -0700199 if (it == mCurrentSlicedCounter->end()) {
Yao Chen729093d2017-10-16 10:33:26 -0700200 // create a counter for the new key
Yang Lu3eba6212017-10-25 19:54:45 -0700201 (*mCurrentSlicedCounter)[eventKey] = 1;
Yao Chen729093d2017-10-16 10:33:26 -0700202 } else {
203 // increment the existing value
204 auto& count = it->second;
205 count++;
206 }
207
Yangster-macd1815dc2017-11-13 21:43:15 -0800208 VLOG("metric %s %s->%d", mMetric.name().c_str(), eventKey.c_str(),
Yang Lu3eba6212017-10-25 19:54:45 -0700209 (*mCurrentSlicedCounter)[eventKey]);
Yao Chen44cf27c2017-09-14 22:32:50 -0700210}
211
Yao Chen729093d2017-10-16 10:33:26 -0700212// When a new matched event comes in, we check if event falls into the current
213// bucket. If not, flush the old counter to past buckets and initialize the new bucket.
214void CountMetricProducer::flushCounterIfNeeded(const uint64_t eventTimeNs) {
215 if (mCurrentBucketStartTimeNs + mBucketSizeNs > eventTimeNs) {
Yao Chen44cf27c2017-09-14 22:32:50 -0700216 return;
217 }
218
Yao Chen44cf27c2017-09-14 22:32:50 -0700219 // adjust the bucket start time
Yang Lu3eba6212017-10-25 19:54:45 -0700220 // TODO: This (and addPastBucket to which it goes) doesn't really need to be an int64.
221 uint64_t numBucketsForward = (eventTimeNs - mCurrentBucketStartTimeNs) / mBucketSizeNs;
Bookatza4bc9c42017-10-04 11:45:57 -0700222
Yao Chen93fe3a32017-11-02 13:52:59 -0700223 CountBucket info;
224 info.mBucketStartNs = mCurrentBucketStartTimeNs;
225 info.mBucketEndNs = mCurrentBucketStartTimeNs + mBucketSizeNs;
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-macd1815dc2017-11-13 21:43:15 -0800230 VLOG("metric %s, dump key value: %s -> %d", mMetric.name().c_str(), counter.first.c_str(),
Yao Chen729093d2017-10-16 10:33:26 -0700231 counter.second);
Yao Chen93fe3a32017-11-02 13:52:59 -0700232 mByteSize += sizeof(info);
Yao Chen729093d2017-10-16 10:33:26 -0700233 }
234
Yang Lu3eba6212017-10-25 19:54:45 -0700235 for (auto& tracker : mAnomalyTrackers) {
236 tracker->addOrUpdateBucket(mCurrentSlicedCounter, mCurrentBucketNum);
237 tracker->declareAndDeclareAnomaly();
238 }
Bookatzd3606c72017-10-19 10:13:49 -0700239
Yang Lu3eba6212017-10-25 19:54:45 -0700240 // Reset counters (do not clear, since the old one is still referenced in mAnomalyTrackers).
241 mCurrentSlicedCounter = std::make_shared<DimToValMap>();
Yao Chen729093d2017-10-16 10:33:26 -0700242
243 mCurrentBucketStartTimeNs = mCurrentBucketStartTimeNs + numBucketsForward * mBucketSizeNs;
Yang Lu3eba6212017-10-25 19:54:45 -0700244 mCurrentBucketNum += numBucketsForward;
Yangster-macd1815dc2017-11-13 21:43:15 -0800245 VLOG("metric %s: new bucket start time: %lld", mMetric.name().c_str(),
Yao Chen729093d2017-10-16 10:33:26 -0700246 (long long)mCurrentBucketStartTimeNs);
Yao Chen44cf27c2017-09-14 22:32:50 -0700247}
248
yro24809bd2017-10-31 23:06:53 -0700249// Rough estimate of CountMetricProducer buffer stored. This number will be
250// greater than actual data size as it contains each dimension of
251// CountMetricData is duplicated.
yro69007c82017-10-26 20:42:57 -0700252size_t CountMetricProducer::byteSize() {
yro24809bd2017-10-31 23:06:53 -0700253 return mByteSize;
yro69007c82017-10-26 20:42:57 -0700254}
255
Yao Chen44cf27c2017-09-14 22:32:50 -0700256} // namespace statsd
257} // namespace os
yro69007c82017-10-26 20:42:57 -0700258} // namespace android