blob: 288f563cc9481fe44cb32dbc5f39a8c49d30a866 [file] [log] [blame]
Yangster1d4d6862017-10-31 12:58:51 -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 Chen3c0b95c2017-12-16 14:34:20 -080017#define DEBUG false // STOPSHIP if true
Yangster1d4d6862017-10-31 12:58:51 -070018#include "Log.h"
19
20#include "GaugeMetricProducer.h"
Yao Chenb3561512017-11-21 18:07:17 -080021#include "guardrail/StatsdStats.h"
Yangster-mac20877162017-12-22 17:19:39 -080022#include "stats_log_util.h"
Yangster1d4d6862017-10-31 12:58:51 -070023
24#include <cutils/log.h>
Yangster1d4d6862017-10-31 12:58:51 -070025
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;
yro2b0f8862017-11-06 14:27:31 -080033using android::util::ProtoOutputStream;
Yangster1d4d6862017-10-31 12:58:51 -070034using std::map;
35using std::string;
36using std::unordered_map;
37using std::vector;
Chenjie Yud9dfda72017-12-11 17:41:20 -080038using std::make_shared;
39using std::shared_ptr;
Yangster1d4d6862017-10-31 12:58:51 -070040
41namespace android {
42namespace os {
43namespace statsd {
44
yro2b0f8862017-11-06 14:27:31 -080045// for StatsLogReport
Yangster-mac94e197c2018-01-02 16:03:03 -080046const int FIELD_ID_ID = 1;
yro2b0f8862017-11-06 14:27:31 -080047const int FIELD_ID_GAUGE_METRICS = 8;
48// for GaugeMetricDataWrapper
49const int FIELD_ID_DATA = 1;
50// for GaugeMetricData
Yangster-mac468ff042018-01-17 12:26:34 -080051const int FIELD_ID_DIMENSION_IN_WHAT = 1;
52const int FIELD_ID_DIMENSION_IN_CONDITION = 2;
53const int FIELD_ID_BUCKET_INFO = 3;
yro2b0f8862017-11-06 14:27:31 -080054// for GaugeBucketInfo
Yangster-mac330af582018-02-08 15:24:38 -080055const int FIELD_ID_START_BUCKET_ELAPSED_NANOS = 1;
56const int FIELD_ID_END_BUCKET_ELAPSED_NANOS = 2;
Chenjie Yud9dfda72017-12-11 17:41:20 -080057const int FIELD_ID_ATOM = 3;
Yangster-mac330af582018-02-08 15:24:38 -080058const int FIELD_ID_ELAPSED_ATOM_TIMESTAMP = 4;
yro2b0f8862017-11-06 14:27:31 -080059
Yao Chenb3561512017-11-21 18:07:17 -080060GaugeMetricProducer::GaugeMetricProducer(const ConfigKey& key, const GaugeMetric& metric,
61 const int conditionIndex,
Yangster-maca070b6a2018-01-04 13:28:38 -080062 const sp<ConditionWizard>& wizard,
Chenjie Yud9dfda72017-12-11 17:41:20 -080063 const int pullTagId, const uint64_t startTimeNs,
64 shared_ptr<StatsPullerManager> statsPullerManager)
Yangster-mac94e197c2018-01-02 16:03:03 -080065 : MetricProducer(metric.id(), key, startTimeNs, conditionIndex, wizard),
Chenjie Yud9dfda72017-12-11 17:41:20 -080066 mStatsPullerManager(statsPullerManager),
Yangster-maca070b6a2018-01-04 13:28:38 -080067 mPullTagId(pullTagId) {
Yangster-mac34ea1102018-01-29 12:40:55 -080068 mCurrentSlicedBucket = std::make_shared<DimToGaugeAtomsMap>();
Yangster-mac20877162017-12-22 17:19:39 -080069 mCurrentSlicedBucketForAnomaly = std::make_shared<DimToValMap>();
Yangster-macb8144812018-01-04 10:56:23 -080070 int64_t bucketSizeMills = 0;
71 if (metric.has_bucket()) {
yro59cc24d2018-02-13 20:17:32 -080072 bucketSizeMills = TimeUnitToBucketSizeInMillisGuardrailed(key.GetUid(), metric.bucket());
Yangster1d4d6862017-10-31 12:58:51 -070073 } else {
Yangster-macb8144812018-01-04 10:56:23 -080074 bucketSizeMills = TimeUnitToBucketSizeInMillis(ONE_HOUR);
Yangster1d4d6862017-10-31 12:58:51 -070075 }
Yangster-macb8144812018-01-04 10:56:23 -080076 mBucketSizeNs = bucketSizeMills * 1000000;
Yangster1d4d6862017-10-31 12:58:51 -070077
Yangster-mac34ea1102018-01-29 12:40:55 -080078 mSamplingType = metric.sampling_type();
Yao Chen8a8d16c2018-02-08 14:50:40 -080079 if (!metric.gauge_fields_filter().include_all()) {
80 translateFieldMatcher(metric.gauge_fields_filter().fields(), &mFieldMatchers);
81 }
Chenjie Yud9dfda72017-12-11 17:41:20 -080082
Yangster1d4d6862017-10-31 12:58:51 -070083 // TODO: use UidMap if uid->pkg_name is required
Yao Chen8a8d16c2018-02-08 14:50:40 -080084 if (metric.has_dimensions_in_what()) {
85 translateFieldMatcher(metric.dimensions_in_what(), &mDimensionsInWhat);
86 }
87
88 if (metric.has_dimensions_in_condition()) {
89 translateFieldMatcher(metric.dimensions_in_condition(), &mDimensionsInCondition);
90 }
Yangster1d4d6862017-10-31 12:58:51 -070091
92 if (metric.links().size() > 0) {
Yao Chen8a8d16c2018-02-08 14:50:40 -080093 for (const auto& link : metric.links()) {
94 Metric2Condition mc;
95 mc.conditionId = link.condition();
96 translateFieldMatcher(link.fields_in_what(), &mc.metricFields);
97 translateFieldMatcher(link.fields_in_condition(), &mc.conditionFields);
98 mMetric2ConditionLinks.push_back(mc);
99 }
Yangster1d4d6862017-10-31 12:58:51 -0700100 }
Yao Chen8a8d16c2018-02-08 14:50:40 -0800101 mConditionSliced = (metric.links().size() > 0) || (mDimensionsInCondition.size() > 0);
Yangster1d4d6862017-10-31 12:58:51 -0700102
103 // Kicks off the puller immediately.
Yangster-mac34ea1102018-01-29 12:40:55 -0800104 if (mPullTagId != -1 && mSamplingType == GaugeMetric::RANDOM_ONE_SAMPLE) {
Yangster-macb8144812018-01-04 10:56:23 -0800105 mStatsPullerManager->RegisterReceiver(mPullTagId, this, bucketSizeMills);
Yangster1d4d6862017-10-31 12:58:51 -0700106 }
107
Yangster-mac94e197c2018-01-02 16:03:03 -0800108 VLOG("metric %lld created. bucket size %lld start_time: %lld", (long long)metric.id(),
Yangster1d4d6862017-10-31 12:58:51 -0700109 (long long)mBucketSizeNs, (long long)mStartTimeNs);
110}
111
Chenjie Yud9dfda72017-12-11 17:41:20 -0800112// for testing
113GaugeMetricProducer::GaugeMetricProducer(const ConfigKey& key, const GaugeMetric& metric,
114 const int conditionIndex,
115 const sp<ConditionWizard>& wizard, const int pullTagId,
Yangster-maca070b6a2018-01-04 13:28:38 -0800116 const int64_t startTimeNs)
117 : GaugeMetricProducer(key, metric, conditionIndex, wizard, pullTagId, startTimeNs,
Chenjie Yud9dfda72017-12-11 17:41:20 -0800118 make_shared<StatsPullerManager>()) {
119}
120
Yangster1d4d6862017-10-31 12:58:51 -0700121GaugeMetricProducer::~GaugeMetricProducer() {
122 VLOG("~GaugeMetricProducer() called");
Chenjie Yu032fefc2017-12-01 23:30:59 -0800123 if (mPullTagId != -1) {
Chenjie Yud9dfda72017-12-11 17:41:20 -0800124 mStatsPullerManager->UnRegisterReceiver(mPullTagId, this);
Chenjie Yu032fefc2017-12-01 23:30:59 -0800125 }
Yangster1d4d6862017-10-31 12:58:51 -0700126}
127
Yao Chen288c6002017-12-12 13:43:18 -0800128void GaugeMetricProducer::onDumpReportLocked(const uint64_t dumpTimeNs,
129 ProtoOutputStream* protoOutput) {
Yangster-mac94e197c2018-01-02 16:03:03 -0800130 VLOG("gauge metric %lld report now...", (long long)mMetricId);
Yao Chen6a8c7992017-11-29 20:02:07 +0000131
Yao Chen288c6002017-12-12 13:43:18 -0800132 flushIfNeededLocked(dumpTimeNs);
Yangster-mac635b4b32018-01-23 20:17:35 -0800133 if (mPastBuckets.empty()) {
134 return;
135 }
Yao Chen288c6002017-12-12 13:43:18 -0800136
Yangster-mac94e197c2018-01-02 16:03:03 -0800137 protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_ID, (long long)mMetricId);
Yi Jin5ee07872018-03-05 18:18:27 -0800138 uint64_t protoToken = protoOutput->start(FIELD_TYPE_MESSAGE | FIELD_ID_GAUGE_METRICS);
Yao Chen6a8c7992017-11-29 20:02:07 +0000139
Yangster1d4d6862017-10-31 12:58:51 -0700140 for (const auto& pair : mPastBuckets) {
Yangster-mac93694462018-01-22 20:49:31 -0800141 const MetricDimensionKey& dimensionKey = pair.first;
Yangster1d4d6862017-10-31 12:58:51 -0700142
Yangster-mac93694462018-01-22 20:49:31 -0800143 VLOG(" dimension key %s", dimensionKey.c_str());
Yi Jin5ee07872018-03-05 18:18:27 -0800144 uint64_t wrapperToken =
Yao Chen288c6002017-12-12 13:43:18 -0800145 protoOutput->start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | FIELD_ID_DATA);
yro2b0f8862017-11-06 14:27:31 -0800146
Yangster-mac20877162017-12-22 17:19:39 -0800147 // First fill dimension.
Yi Jin5ee07872018-03-05 18:18:27 -0800148 uint64_t dimensionToken = protoOutput->start(
Yangster-mac468ff042018-01-17 12:26:34 -0800149 FIELD_TYPE_MESSAGE | FIELD_ID_DIMENSION_IN_WHAT);
Yao Chen8a8d16c2018-02-08 14:50:40 -0800150 writeDimensionToProto(dimensionKey.getDimensionKeyInWhat(), protoOutput);
Yangster-mac20877162017-12-22 17:19:39 -0800151 protoOutput->end(dimensionToken);
yro2b0f8862017-11-06 14:27:31 -0800152
Yangster-mac93694462018-01-22 20:49:31 -0800153 if (dimensionKey.hasDimensionKeyInCondition()) {
Yi Jin5ee07872018-03-05 18:18:27 -0800154 uint64_t dimensionInConditionToken = protoOutput->start(
Yangster-mac93694462018-01-22 20:49:31 -0800155 FIELD_TYPE_MESSAGE | FIELD_ID_DIMENSION_IN_CONDITION);
Yao Chen8a8d16c2018-02-08 14:50:40 -0800156 writeDimensionToProto(dimensionKey.getDimensionKeyInCondition(), protoOutput);
Yangster-mac93694462018-01-22 20:49:31 -0800157 protoOutput->end(dimensionInConditionToken);
158 }
159
yro2b0f8862017-11-06 14:27:31 -0800160 // Then fill bucket_info (GaugeBucketInfo).
161 for (const auto& bucket : pair.second) {
Yi Jin5ee07872018-03-05 18:18:27 -0800162 uint64_t bucketInfoToken = protoOutput->start(
Yao Chen288c6002017-12-12 13:43:18 -0800163 FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | FIELD_ID_BUCKET_INFO);
Yangster-mac330af582018-02-08 15:24:38 -0800164 protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_START_BUCKET_ELAPSED_NANOS,
Yao Chen288c6002017-12-12 13:43:18 -0800165 (long long)bucket.mBucketStartNs);
Yangster-mac330af582018-02-08 15:24:38 -0800166 protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_END_BUCKET_ELAPSED_NANOS,
Yao Chen288c6002017-12-12 13:43:18 -0800167 (long long)bucket.mBucketEndNs);
Yangster-mac34ea1102018-01-29 12:40:55 -0800168
169 if (!bucket.mGaugeAtoms.empty()) {
Yi Jin5ee07872018-03-05 18:18:27 -0800170 uint64_t atomsToken =
Yangster-mac34ea1102018-01-29 12:40:55 -0800171 protoOutput->start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | FIELD_ID_ATOM);
172 for (const auto& atom : bucket.mGaugeAtoms) {
Yao Chen8a8d16c2018-02-08 14:50:40 -0800173 writeFieldValueTreeToStream(mTagId, *(atom.mFields), protoOutput);
Yangster-mac34ea1102018-01-29 12:40:55 -0800174 }
175 protoOutput->end(atomsToken);
Yangster-mac34ea1102018-01-29 12:40:55 -0800176 for (const auto& atom : bucket.mGaugeAtoms) {
Yangster-macd5c35622018-02-02 10:33:25 -0800177 const bool truncateTimestamp =
178 android::util::kNotTruncatingTimestampAtomWhiteList.find(mTagId) ==
179 android::util::kNotTruncatingTimestampAtomWhiteList.end();
180 int64_t timestampNs = truncateTimestamp ?
181 truncateTimestampNsToFiveMinutes(atom.mTimestamps) : atom.mTimestamps;
Yangster-mac330af582018-02-08 15:24:38 -0800182 protoOutput->write(
183 FIELD_TYPE_INT64 | FIELD_COUNT_REPEATED | FIELD_ID_ELAPSED_ATOM_TIMESTAMP,
Yangster-macd5c35622018-02-02 10:33:25 -0800184 (long long)timestampNs);
Yangster-mac34ea1102018-01-29 12:40:55 -0800185 }
186 }
Yao Chen288c6002017-12-12 13:43:18 -0800187 protoOutput->end(bucketInfoToken);
Yangster-mac34ea1102018-01-29 12:40:55 -0800188 VLOG("\t bucket [%lld - %lld] includes %d atoms.", (long long)bucket.mBucketStartNs,
189 (long long)bucket.mBucketEndNs, (int)bucket.mGaugeAtoms.size());
yro2b0f8862017-11-06 14:27:31 -0800190 }
Yao Chen288c6002017-12-12 13:43:18 -0800191 protoOutput->end(wrapperToken);
Yangster1d4d6862017-10-31 12:58:51 -0700192 }
Yao Chen288c6002017-12-12 13:43:18 -0800193 protoOutput->end(protoToken);
yro2b0f8862017-11-06 14:27:31 -0800194
Yao Chen6a8c7992017-11-29 20:02:07 +0000195 mPastBuckets.clear();
yro2b0f8862017-11-06 14:27:31 -0800196 // TODO: Clear mDimensionKeyMap once the report is dumped.
Yangster1d4d6862017-10-31 12:58:51 -0700197}
198
David Chen27785a82018-01-19 17:06:45 -0800199void GaugeMetricProducer::pullLocked() {
200 vector<std::shared_ptr<LogEvent>> allData;
201 if (!mStatsPullerManager->Pull(mPullTagId, &allData)) {
202 ALOGE("Stats puller failed for tag: %d", mPullTagId);
203 return;
204 }
205 for (const auto& data : allData) {
206 onMatchedLogEventLocked(0, *data);
207 }
208}
209
Yangsterf2bee6f2017-11-29 12:01:05 -0800210void GaugeMetricProducer::onConditionChangedLocked(const bool conditionMet,
211 const uint64_t eventTime) {
Yangster-mac94e197c2018-01-02 16:03:03 -0800212 VLOG("Metric %lld onConditionChanged", (long long)mMetricId);
Yangsterf2bee6f2017-11-29 12:01:05 -0800213 flushIfNeededLocked(eventTime);
Yao Chen6a8c7992017-11-29 20:02:07 +0000214 mCondition = conditionMet;
Yangster8de69392017-11-27 13:48:29 -0800215
Yao Chen6a8c7992017-11-29 20:02:07 +0000216 // Push mode. No need to proactively pull the gauge data.
217 if (mPullTagId == -1) {
218 return;
Yangster1d4d6862017-10-31 12:58:51 -0700219 }
Yangster-mac34ea1102018-01-29 12:40:55 -0800220
221 bool triggerPuller = false;
222 switch(mSamplingType) {
223 // When the metric wants to do random sampling and there is already one gauge atom for the
224 // current bucket, do not do it again.
225 case GaugeMetric::RANDOM_ONE_SAMPLE: {
226 triggerPuller = mCondition && mCurrentSlicedBucket->empty();
227 break;
228 }
229 case GaugeMetric::ALL_CONDITION_CHANGES: {
230 triggerPuller = true;
231 break;
232 }
233 default:
234 break;
235 }
236 if (!triggerPuller) {
Yao Chen6a8c7992017-11-29 20:02:07 +0000237 return;
238 }
Yangster-mac34ea1102018-01-29 12:40:55 -0800239
Yao Chen6a8c7992017-11-29 20:02:07 +0000240 vector<std::shared_ptr<LogEvent>> allData;
Chenjie Yud9dfda72017-12-11 17:41:20 -0800241 if (!mStatsPullerManager->Pull(mPullTagId, &allData)) {
Yao Chen6a8c7992017-11-29 20:02:07 +0000242 ALOGE("Stats puller failed for tag: %d", mPullTagId);
243 return;
244 }
Yangster1d4d6862017-10-31 12:58:51 -0700245 for (const auto& data : allData) {
Chenjie Yua7259ab2017-12-10 08:31:05 -0800246 onMatchedLogEventLocked(0, *data);
Yangster1d4d6862017-10-31 12:58:51 -0700247 }
Yangsterf2bee6f2017-11-29 12:01:05 -0800248 flushIfNeededLocked(eventTime);
Yangster1d4d6862017-10-31 12:58:51 -0700249}
250
Yangsterf2bee6f2017-11-29 12:01:05 -0800251void GaugeMetricProducer::onSlicedConditionMayChangeLocked(const uint64_t eventTime) {
Yangster-mac94e197c2018-01-02 16:03:03 -0800252 VLOG("Metric %lld onSlicedConditionMayChange", (long long)mMetricId);
Yangster1d4d6862017-10-31 12:58:51 -0700253}
254
Yao Chen8a8d16c2018-02-08 14:50:40 -0800255std::shared_ptr<vector<FieldValue>> GaugeMetricProducer::getGaugeFields(const LogEvent& event) {
256 if (mFieldMatchers.size() > 0) {
257 std::shared_ptr<vector<FieldValue>> gaugeFields = std::make_shared<vector<FieldValue>>();
258 filterGaugeValues(mFieldMatchers, event.getValues(), gaugeFields.get());
259 return gaugeFields;
260 } else {
261 return std::make_shared<vector<FieldValue>>(event.getValues());
Yangster1d4d6862017-10-31 12:58:51 -0700262 }
263}
264
265void GaugeMetricProducer::onDataPulled(const std::vector<std::shared_ptr<LogEvent>>& allData) {
Yangsterf2bee6f2017-11-29 12:01:05 -0800266 std::lock_guard<std::mutex> lock(mMutex);
Chenjie Yud9dfda72017-12-11 17:41:20 -0800267 if (allData.size() == 0) {
268 return;
269 }
Yangster1d4d6862017-10-31 12:58:51 -0700270 for (const auto& data : allData) {
Chenjie Yua7259ab2017-12-10 08:31:05 -0800271 onMatchedLogEventLocked(0, *data);
Yangster1d4d6862017-10-31 12:58:51 -0700272 }
Yangster1d4d6862017-10-31 12:58:51 -0700273}
274
Yangster-mac93694462018-01-22 20:49:31 -0800275bool GaugeMetricProducer::hitGuardRailLocked(const MetricDimensionKey& newKey) {
Yao Chenb3561512017-11-21 18:07:17 -0800276 if (mCurrentSlicedBucket->find(newKey) != mCurrentSlicedBucket->end()) {
277 return false;
278 }
279 // 1. Report the tuple count if the tuple count > soft limit
280 if (mCurrentSlicedBucket->size() > StatsdStats::kDimensionKeySizeSoftLimit - 1) {
281 size_t newTupleCount = mCurrentSlicedBucket->size() + 1;
Yangster-mac94e197c2018-01-02 16:03:03 -0800282 StatsdStats::getInstance().noteMetricDimensionSize(mConfigKey, mMetricId, newTupleCount);
Yao Chenb3561512017-11-21 18:07:17 -0800283 // 2. Don't add more tuples, we are above the allowed threshold. Drop the data.
284 if (newTupleCount > StatsdStats::kDimensionKeySizeHardLimit) {
Yangster-mac94e197c2018-01-02 16:03:03 -0800285 ALOGE("GaugeMetric %lld dropping data for dimension key %s",
286 (long long)mMetricId, newKey.c_str());
Yao Chenb3561512017-11-21 18:07:17 -0800287 return true;
288 }
289 }
290
291 return false;
292}
293
Yangsterf2bee6f2017-11-29 12:01:05 -0800294void GaugeMetricProducer::onMatchedLogEventInternalLocked(
Yangster-mac93694462018-01-22 20:49:31 -0800295 const size_t matcherIndex, const MetricDimensionKey& eventKey,
Yangster-mac20877162017-12-22 17:19:39 -0800296 const ConditionKey& conditionKey, bool condition,
Chenjie Yua7259ab2017-12-10 08:31:05 -0800297 const LogEvent& event) {
Yangster1d4d6862017-10-31 12:58:51 -0700298 if (condition == false) {
299 return;
300 }
Yangster-mac330af582018-02-08 15:24:38 -0800301 uint64_t eventTimeNs = event.GetElapsedTimestampNs();
Yao Chen8a8d16c2018-02-08 14:50:40 -0800302 mTagId = event.GetTagId();
Yangster1d4d6862017-10-31 12:58:51 -0700303 if (eventTimeNs < mCurrentBucketStartTimeNs) {
304 VLOG("Skip event due to late arrival: %lld vs %lld", (long long)eventTimeNs,
305 (long long)mCurrentBucketStartTimeNs);
306 return;
307 }
Chenjie Yud9dfda72017-12-11 17:41:20 -0800308 flushIfNeededLocked(eventTimeNs);
Yao Chen6a8c7992017-11-29 20:02:07 +0000309
Yangster-mac34ea1102018-01-29 12:40:55 -0800310 // When gauge metric wants to randomly sample the output atom, we just simply use the first
311 // gauge in the given bucket.
312 if (mCurrentSlicedBucket->find(eventKey) != mCurrentSlicedBucket->end() &&
313 mSamplingType == GaugeMetric::RANDOM_ONE_SAMPLE) {
Yangster1d4d6862017-10-31 12:58:51 -0700314 return;
315 }
Chenjie Yud9dfda72017-12-11 17:41:20 -0800316 if (hitGuardRailLocked(eventKey)) {
317 return;
Yao Chen6a8c7992017-11-29 20:02:07 +0000318 }
Yao Chen8a8d16c2018-02-08 14:50:40 -0800319 GaugeAtom gaugeAtom(getGaugeFields(event), eventTimeNs);
Yangster-mac34ea1102018-01-29 12:40:55 -0800320 (*mCurrentSlicedBucket)[eventKey].push_back(gaugeAtom);
Chenjie Yud9dfda72017-12-11 17:41:20 -0800321 // Anomaly detection on gauge metric only works when there is one numeric
322 // field specified.
323 if (mAnomalyTrackers.size() > 0) {
Yangster-mac34ea1102018-01-29 12:40:55 -0800324 if (gaugeAtom.mFields->size() == 1) {
Yao Chen8a8d16c2018-02-08 14:50:40 -0800325 const Value& value = gaugeAtom.mFields->begin()->mValue;
Chenjie Yud9dfda72017-12-11 17:41:20 -0800326 long gaugeVal = 0;
Yao Chen8a8d16c2018-02-08 14:50:40 -0800327 if (value.getType() == INT) {
328 gaugeVal = (long)value.int_value;
329 } else if (value.getType() == LONG) {
330 gaugeVal = value.long_value;
Chenjie Yud9dfda72017-12-11 17:41:20 -0800331 }
332 for (auto& tracker : mAnomalyTrackers) {
333 tracker->detectAndDeclareAnomaly(eventTimeNs, mCurrentBucketNum, eventKey,
334 gaugeVal);
335 }
336 }
337 }
338}
339
340void GaugeMetricProducer::updateCurrentSlicedBucketForAnomaly() {
Chenjie Yud9dfda72017-12-11 17:41:20 -0800341 for (const auto& slice : *mCurrentSlicedBucket) {
Yao Chen8a8d16c2018-02-08 14:50:40 -0800342 if (slice.second.empty()) {
Yangster-mac34ea1102018-01-29 12:40:55 -0800343 continue;
344 }
Yao Chen8a8d16c2018-02-08 14:50:40 -0800345 const Value& value = slice.second.front().mFields->front().mValue;
Chenjie Yud9dfda72017-12-11 17:41:20 -0800346 long gaugeVal = 0;
Yao Chen8a8d16c2018-02-08 14:50:40 -0800347 if (value.getType() == INT) {
348 gaugeVal = (long)value.int_value;
349 } else if (value.getType() == LONG) {
350 gaugeVal = value.long_value;
Chenjie Yud9dfda72017-12-11 17:41:20 -0800351 }
352 (*mCurrentSlicedBucketForAnomaly)[slice.first] = gaugeVal;
Yangster1d4d6862017-10-31 12:58:51 -0700353 }
354}
355
Yao Chen06dba5d2018-01-26 13:38:16 -0800356void GaugeMetricProducer::dropDataLocked(const uint64_t dropTimeNs) {
357 flushIfNeededLocked(dropTimeNs);
358 mPastBuckets.clear();
359}
360
Yangster1d4d6862017-10-31 12:58:51 -0700361// When a new matched event comes in, we check if event falls into the current
362// bucket. If not, flush the old counter to past buckets and initialize the new
363// bucket.
364// if data is pushed, onMatchedLogEvent will only be called through onConditionChanged() inside
365// the GaugeMetricProducer while holding the lock.
Yangsterf2bee6f2017-11-29 12:01:05 -0800366void GaugeMetricProducer::flushIfNeededLocked(const uint64_t& eventTimeNs) {
David Chen27785a82018-01-19 17:06:45 -0800367 uint64_t currentBucketEndTimeNs = getCurrentBucketEndTimeNs();
368
369 if (eventTimeNs < currentBucketEndTimeNs) {
Chenjie Yud9dfda72017-12-11 17:41:20 -0800370 VLOG("eventTime is %lld, less than next bucket start time %lld", (long long)eventTimeNs,
371 (long long)(mCurrentBucketStartTimeNs + mBucketSizeNs));
Yangster1d4d6862017-10-31 12:58:51 -0700372 return;
373 }
374
David Chen27785a82018-01-19 17:06:45 -0800375 flushCurrentBucketLocked(eventTimeNs);
376
377 // Adjusts the bucket start and end times.
378 int64_t numBucketsForward = 1 + (eventTimeNs - currentBucketEndTimeNs) / mBucketSizeNs;
379 mCurrentBucketStartTimeNs = currentBucketEndTimeNs + (numBucketsForward - 1) * mBucketSizeNs;
380 mCurrentBucketNum += numBucketsForward;
381 VLOG("metric %lld: new bucket start time: %lld", (long long)mMetricId,
382 (long long)mCurrentBucketStartTimeNs);
383}
384
385void GaugeMetricProducer::flushCurrentBucketLocked(const uint64_t& eventTimeNs) {
386 uint64_t fullBucketEndTimeNs = getCurrentBucketEndTimeNs();
387
yro2b0f8862017-11-06 14:27:31 -0800388 GaugeBucket info;
389 info.mBucketStartNs = mCurrentBucketStartTimeNs;
David Chen27785a82018-01-19 17:06:45 -0800390 if (eventTimeNs < fullBucketEndTimeNs) {
391 info.mBucketEndNs = eventTimeNs;
392 } else {
393 info.mBucketEndNs = fullBucketEndTimeNs;
394 }
Yangster-mace2cd6d52017-11-09 20:38:30 -0800395 info.mBucketNum = mCurrentBucketNum;
Yangster1d4d6862017-10-31 12:58:51 -0700396
Yangster-mace2cd6d52017-11-09 20:38:30 -0800397 for (const auto& slice : *mCurrentSlicedBucket) {
Yangster-mac34ea1102018-01-29 12:40:55 -0800398 info.mGaugeAtoms = slice.second;
Yangster1d4d6862017-10-31 12:58:51 -0700399 auto& bucketList = mPastBuckets[slice.first];
400 bucketList.push_back(info);
David Chen27785a82018-01-19 17:06:45 -0800401 VLOG("gauge metric %lld, dump key value: %s", (long long)mMetricId, slice.first.c_str());
Yangster1d4d6862017-10-31 12:58:51 -0700402 }
Yangster1d4d6862017-10-31 12:58:51 -0700403
David Chen27785a82018-01-19 17:06:45 -0800404 // If we have anomaly trackers, we need to update the partial bucket values.
Chenjie Yud9dfda72017-12-11 17:41:20 -0800405 if (mAnomalyTrackers.size() > 0) {
406 updateCurrentSlicedBucketForAnomaly();
David Chen27785a82018-01-19 17:06:45 -0800407
408 if (eventTimeNs > fullBucketEndTimeNs) {
409 // This is known to be a full bucket, so send this data to the anomaly tracker.
410 for (auto& tracker : mAnomalyTrackers) {
411 tracker->addPastBucket(mCurrentSlicedBucketForAnomaly, mCurrentBucketNum);
412 }
413 mCurrentSlicedBucketForAnomaly = std::make_shared<DimToValMap>();
Chenjie Yud9dfda72017-12-11 17:41:20 -0800414 }
Yangster-mace2cd6d52017-11-09 20:38:30 -0800415 }
416
Yangster-mac34ea1102018-01-29 12:40:55 -0800417 mCurrentSlicedBucket = std::make_shared<DimToGaugeAtomsMap>();
Yangster1d4d6862017-10-31 12:58:51 -0700418}
419
Yangsterf2bee6f2017-11-29 12:01:05 -0800420size_t GaugeMetricProducer::byteSizeLocked() const {
Yangster-mace2cd6d52017-11-09 20:38:30 -0800421 size_t totalSize = 0;
422 for (const auto& pair : mPastBuckets) {
423 totalSize += pair.second.size() * kBucketSize;
424 }
425 return totalSize;
yro2b0f8862017-11-06 14:27:31 -0800426}
427
Yangster1d4d6862017-10-31 12:58:51 -0700428} // namespace statsd
429} // namespace os
430} // namespace android