blob: 4190f0048cc2a8ecc943a39b01971aaeda31b2c3 [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 "dimension.h"
23#include "stats_log_util.h"
Yangster1d4d6862017-10-31 12:58:51 -070024
25#include <cutils/log.h>
Yangster1d4d6862017-10-31 12:58:51 -070026
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;
yro2b0f8862017-11-06 14:27:31 -080034using android::util::ProtoOutputStream;
Yangster1d4d6862017-10-31 12:58:51 -070035using std::map;
36using std::string;
37using std::unordered_map;
38using std::vector;
Chenjie Yud9dfda72017-12-11 17:41:20 -080039using std::make_shared;
40using std::shared_ptr;
Yangster1d4d6862017-10-31 12:58:51 -070041
42namespace android {
43namespace os {
44namespace statsd {
45
yro2b0f8862017-11-06 14:27:31 -080046// for StatsLogReport
Yangster-mac94e197c2018-01-02 16:03:03 -080047const int FIELD_ID_ID = 1;
yro2b0f8862017-11-06 14:27:31 -080048const int FIELD_ID_START_REPORT_NANOS = 2;
49const int FIELD_ID_END_REPORT_NANOS = 3;
50const int FIELD_ID_GAUGE_METRICS = 8;
51// for GaugeMetricDataWrapper
52const int FIELD_ID_DATA = 1;
53// for GaugeMetricData
Yangster-mac468ff042018-01-17 12:26:34 -080054const int FIELD_ID_DIMENSION_IN_WHAT = 1;
55const int FIELD_ID_DIMENSION_IN_CONDITION = 2;
56const int FIELD_ID_BUCKET_INFO = 3;
yro2b0f8862017-11-06 14:27:31 -080057// for GaugeBucketInfo
58const int FIELD_ID_START_BUCKET_NANOS = 1;
59const int FIELD_ID_END_BUCKET_NANOS = 2;
Chenjie Yud9dfda72017-12-11 17:41:20 -080060const int FIELD_ID_ATOM = 3;
Yangster-mac34ea1102018-01-29 12:40:55 -080061const int FIELD_ID_TIMESTAMP = 4;
yro2b0f8862017-11-06 14:27:31 -080062
Yao Chenb3561512017-11-21 18:07:17 -080063GaugeMetricProducer::GaugeMetricProducer(const ConfigKey& key, const GaugeMetric& metric,
64 const int conditionIndex,
Yangster-maca070b6a2018-01-04 13:28:38 -080065 const sp<ConditionWizard>& wizard,
Chenjie Yud9dfda72017-12-11 17:41:20 -080066 const int pullTagId, const uint64_t startTimeNs,
67 shared_ptr<StatsPullerManager> statsPullerManager)
Yangster-mac94e197c2018-01-02 16:03:03 -080068 : MetricProducer(metric.id(), key, startTimeNs, conditionIndex, wizard),
Chenjie Yud9dfda72017-12-11 17:41:20 -080069 mStatsPullerManager(statsPullerManager),
Yangster-maca070b6a2018-01-04 13:28:38 -080070 mPullTagId(pullTagId) {
Yangster-mac34ea1102018-01-29 12:40:55 -080071 mCurrentSlicedBucket = std::make_shared<DimToGaugeAtomsMap>();
Yangster-mac20877162017-12-22 17:19:39 -080072 mCurrentSlicedBucketForAnomaly = std::make_shared<DimToValMap>();
Yangster-macb8144812018-01-04 10:56:23 -080073 int64_t bucketSizeMills = 0;
74 if (metric.has_bucket()) {
75 bucketSizeMills = TimeUnitToBucketSizeInMillis(metric.bucket());
Yangster1d4d6862017-10-31 12:58:51 -070076 } else {
Yangster-macb8144812018-01-04 10:56:23 -080077 bucketSizeMills = TimeUnitToBucketSizeInMillis(ONE_HOUR);
Yangster1d4d6862017-10-31 12:58:51 -070078 }
Yangster-macb8144812018-01-04 10:56:23 -080079 mBucketSizeNs = bucketSizeMills * 1000000;
Yangster1d4d6862017-10-31 12:58:51 -070080
Yangster-mac34ea1102018-01-29 12:40:55 -080081 mSamplingType = metric.sampling_type();
Yangster-mac20877162017-12-22 17:19:39 -080082 mFieldFilter = metric.gauge_fields_filter();
Chenjie Yud9dfda72017-12-11 17:41:20 -080083
Yangster1d4d6862017-10-31 12:58:51 -070084 // TODO: use UidMap if uid->pkg_name is required
Yangster-mac93694462018-01-22 20:49:31 -080085 mDimensionsInWhat = metric.dimensions_in_what();
86 mDimensionsInCondition = metric.dimensions_in_condition();
Yangster1d4d6862017-10-31 12:58:51 -070087
88 if (metric.links().size() > 0) {
89 mConditionLinks.insert(mConditionLinks.begin(), metric.links().begin(),
90 metric.links().end());
Yangster1d4d6862017-10-31 12:58:51 -070091 }
Yangster-mac93694462018-01-22 20:49:31 -080092 mConditionSliced = (metric.links().size() > 0)||
93 (mDimensionsInCondition.has_field() && mDimensionsInCondition.child_size() > 0);
Yangster1d4d6862017-10-31 12:58:51 -070094
95 // Kicks off the puller immediately.
Yangster-mac34ea1102018-01-29 12:40:55 -080096 if (mPullTagId != -1 && mSamplingType == GaugeMetric::RANDOM_ONE_SAMPLE) {
Yangster-macb8144812018-01-04 10:56:23 -080097 mStatsPullerManager->RegisterReceiver(mPullTagId, this, bucketSizeMills);
Yangster1d4d6862017-10-31 12:58:51 -070098 }
99
Yangster-mac94e197c2018-01-02 16:03:03 -0800100 VLOG("metric %lld created. bucket size %lld start_time: %lld", (long long)metric.id(),
Yangster1d4d6862017-10-31 12:58:51 -0700101 (long long)mBucketSizeNs, (long long)mStartTimeNs);
102}
103
Chenjie Yud9dfda72017-12-11 17:41:20 -0800104// for testing
105GaugeMetricProducer::GaugeMetricProducer(const ConfigKey& key, const GaugeMetric& metric,
106 const int conditionIndex,
107 const sp<ConditionWizard>& wizard, const int pullTagId,
Yangster-maca070b6a2018-01-04 13:28:38 -0800108 const int64_t startTimeNs)
109 : GaugeMetricProducer(key, metric, conditionIndex, wizard, pullTagId, startTimeNs,
Chenjie Yud9dfda72017-12-11 17:41:20 -0800110 make_shared<StatsPullerManager>()) {
111}
112
Yangster1d4d6862017-10-31 12:58:51 -0700113GaugeMetricProducer::~GaugeMetricProducer() {
114 VLOG("~GaugeMetricProducer() called");
Chenjie Yu032fefc2017-12-01 23:30:59 -0800115 if (mPullTagId != -1) {
Chenjie Yud9dfda72017-12-11 17:41:20 -0800116 mStatsPullerManager->UnRegisterReceiver(mPullTagId, this);
Chenjie Yu032fefc2017-12-01 23:30:59 -0800117 }
Yangster1d4d6862017-10-31 12:58:51 -0700118}
119
Yangster-mac20877162017-12-22 17:19:39 -0800120void GaugeMetricProducer::onDumpReportLocked(const uint64_t dumpTimeNs, StatsLogReport* report) {
121 flushIfNeededLocked(dumpTimeNs);
Yangster-mac87718e22018-01-11 16:16:26 -0800122 ProtoOutputStream pbOutput;
123 onDumpReportLocked(dumpTimeNs, &pbOutput);
124 parseProtoOutputStream(pbOutput, report);
Yangster-mac20877162017-12-22 17:19:39 -0800125}
126
Yao Chen288c6002017-12-12 13:43:18 -0800127void GaugeMetricProducer::onDumpReportLocked(const uint64_t dumpTimeNs,
128 ProtoOutputStream* protoOutput) {
Yangster-mac94e197c2018-01-02 16:03:03 -0800129 VLOG("gauge metric %lld report now...", (long long)mMetricId);
Yao Chen6a8c7992017-11-29 20:02:07 +0000130
Yao Chen288c6002017-12-12 13:43:18 -0800131 flushIfNeededLocked(dumpTimeNs);
Yangster-mac635b4b32018-01-23 20:17:35 -0800132 if (mPastBuckets.empty()) {
133 return;
134 }
Yao Chen288c6002017-12-12 13:43:18 -0800135
Yangster-mac94e197c2018-01-02 16:03:03 -0800136 protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_ID, (long long)mMetricId);
Yao Chen288c6002017-12-12 13:43:18 -0800137 protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_START_REPORT_NANOS, (long long)mStartTimeNs);
138 long long 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());
yrob0378b02017-11-09 20:36:25 -0800144 long long 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.
148 long long dimensionToken = protoOutput->start(
Yangster-mac468ff042018-01-17 12:26:34 -0800149 FIELD_TYPE_MESSAGE | FIELD_ID_DIMENSION_IN_WHAT);
Yangster-mac93694462018-01-22 20:49:31 -0800150 writeDimensionsValueProtoToStream(
151 dimensionKey.getDimensionKeyInWhat().getDimensionsValue(), protoOutput);
Yangster-mac20877162017-12-22 17:19:39 -0800152 protoOutput->end(dimensionToken);
yro2b0f8862017-11-06 14:27:31 -0800153
Yangster-mac93694462018-01-22 20:49:31 -0800154 if (dimensionKey.hasDimensionKeyInCondition()) {
155 long long dimensionInConditionToken = protoOutput->start(
156 FIELD_TYPE_MESSAGE | FIELD_ID_DIMENSION_IN_CONDITION);
157 writeDimensionsValueProtoToStream(
158 dimensionKey.getDimensionKeyInCondition().getDimensionsValue(), protoOutput);
159 protoOutput->end(dimensionInConditionToken);
160 }
161
yro2b0f8862017-11-06 14:27:31 -0800162 // Then fill bucket_info (GaugeBucketInfo).
163 for (const auto& bucket : pair.second) {
Yao Chen288c6002017-12-12 13:43:18 -0800164 long long bucketInfoToken = protoOutput->start(
165 FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | FIELD_ID_BUCKET_INFO);
166 protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_START_BUCKET_NANOS,
167 (long long)bucket.mBucketStartNs);
168 protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_END_BUCKET_NANOS,
169 (long long)bucket.mBucketEndNs);
Yangster-mac34ea1102018-01-29 12:40:55 -0800170
171 if (!bucket.mGaugeAtoms.empty()) {
172 long long atomsToken =
173 protoOutput->start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | FIELD_ID_ATOM);
174 for (const auto& atom : bucket.mGaugeAtoms) {
175 writeFieldValueTreeToStream(*atom.mFields, protoOutput);
176 }
177 protoOutput->end(atomsToken);
178
179 for (const auto& atom : bucket.mGaugeAtoms) {
180 protoOutput->write(FIELD_TYPE_INT64 | FIELD_COUNT_REPEATED | FIELD_ID_TIMESTAMP,
181 (long long)atom.mTimestamps);
182 }
183 }
Yao Chen288c6002017-12-12 13:43:18 -0800184 protoOutput->end(bucketInfoToken);
Yangster-mac34ea1102018-01-29 12:40:55 -0800185 VLOG("\t bucket [%lld - %lld] includes %d atoms.", (long long)bucket.mBucketStartNs,
186 (long long)bucket.mBucketEndNs, (int)bucket.mGaugeAtoms.size());
yro2b0f8862017-11-06 14:27:31 -0800187 }
Yao Chen288c6002017-12-12 13:43:18 -0800188 protoOutput->end(wrapperToken);
Yangster1d4d6862017-10-31 12:58:51 -0700189 }
Yao Chen288c6002017-12-12 13:43:18 -0800190 protoOutput->end(protoToken);
191 protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_END_REPORT_NANOS, (long long)dumpTimeNs);
yro2b0f8862017-11-06 14:27:31 -0800192
Yao Chen6a8c7992017-11-29 20:02:07 +0000193 mPastBuckets.clear();
yro2b0f8862017-11-06 14:27:31 -0800194 // TODO: Clear mDimensionKeyMap once the report is dumped.
Yangster1d4d6862017-10-31 12:58:51 -0700195}
196
David Chen27785a82018-01-19 17:06:45 -0800197void GaugeMetricProducer::pullLocked() {
198 vector<std::shared_ptr<LogEvent>> allData;
199 if (!mStatsPullerManager->Pull(mPullTagId, &allData)) {
200 ALOGE("Stats puller failed for tag: %d", mPullTagId);
201 return;
202 }
203 for (const auto& data : allData) {
204 onMatchedLogEventLocked(0, *data);
205 }
206}
207
Yangsterf2bee6f2017-11-29 12:01:05 -0800208void GaugeMetricProducer::onConditionChangedLocked(const bool conditionMet,
209 const uint64_t eventTime) {
Yangster-mac94e197c2018-01-02 16:03:03 -0800210 VLOG("Metric %lld onConditionChanged", (long long)mMetricId);
Yangsterf2bee6f2017-11-29 12:01:05 -0800211 flushIfNeededLocked(eventTime);
Yao Chen6a8c7992017-11-29 20:02:07 +0000212 mCondition = conditionMet;
Yangster8de69392017-11-27 13:48:29 -0800213
Yao Chen6a8c7992017-11-29 20:02:07 +0000214 // Push mode. No need to proactively pull the gauge data.
215 if (mPullTagId == -1) {
216 return;
Yangster1d4d6862017-10-31 12:58:51 -0700217 }
Yangster-mac34ea1102018-01-29 12:40:55 -0800218
219 bool triggerPuller = false;
220 switch(mSamplingType) {
221 // When the metric wants to do random sampling and there is already one gauge atom for the
222 // current bucket, do not do it again.
223 case GaugeMetric::RANDOM_ONE_SAMPLE: {
224 triggerPuller = mCondition && mCurrentSlicedBucket->empty();
225 break;
226 }
227 case GaugeMetric::ALL_CONDITION_CHANGES: {
228 triggerPuller = true;
229 break;
230 }
231 default:
232 break;
233 }
234 if (!triggerPuller) {
Yao Chen6a8c7992017-11-29 20:02:07 +0000235 return;
236 }
Yangster-mac34ea1102018-01-29 12:40:55 -0800237
Yao Chen6a8c7992017-11-29 20:02:07 +0000238 vector<std::shared_ptr<LogEvent>> allData;
Chenjie Yud9dfda72017-12-11 17:41:20 -0800239 if (!mStatsPullerManager->Pull(mPullTagId, &allData)) {
Yao Chen6a8c7992017-11-29 20:02:07 +0000240 ALOGE("Stats puller failed for tag: %d", mPullTagId);
241 return;
242 }
Yangster1d4d6862017-10-31 12:58:51 -0700243 for (const auto& data : allData) {
Chenjie Yua7259ab2017-12-10 08:31:05 -0800244 onMatchedLogEventLocked(0, *data);
Yangster1d4d6862017-10-31 12:58:51 -0700245 }
Yangsterf2bee6f2017-11-29 12:01:05 -0800246 flushIfNeededLocked(eventTime);
Yangster1d4d6862017-10-31 12:58:51 -0700247}
248
Yangsterf2bee6f2017-11-29 12:01:05 -0800249void GaugeMetricProducer::onSlicedConditionMayChangeLocked(const uint64_t eventTime) {
Yangster-mac94e197c2018-01-02 16:03:03 -0800250 VLOG("Metric %lld onSlicedConditionMayChange", (long long)mMetricId);
Yangster1d4d6862017-10-31 12:58:51 -0700251}
252
Yangster-mac20877162017-12-22 17:19:39 -0800253std::shared_ptr<FieldValueMap> GaugeMetricProducer::getGaugeFields(const LogEvent& event) {
254 std::shared_ptr<FieldValueMap> gaugeFields =
255 std::make_shared<FieldValueMap>(event.getFieldValueMap());
256 if (!mFieldFilter.include_all()) {
257 filterFields(mFieldFilter.fields(), gaugeFields.get());
Yangster1d4d6862017-10-31 12:58:51 -0700258 }
Yangster-mac20877162017-12-22 17:19:39 -0800259 return gaugeFields;
Yangster1d4d6862017-10-31 12:58:51 -0700260}
261
262void GaugeMetricProducer::onDataPulled(const std::vector<std::shared_ptr<LogEvent>>& allData) {
Yangsterf2bee6f2017-11-29 12:01:05 -0800263 std::lock_guard<std::mutex> lock(mMutex);
Chenjie Yud9dfda72017-12-11 17:41:20 -0800264 if (allData.size() == 0) {
265 return;
266 }
Yangster1d4d6862017-10-31 12:58:51 -0700267 for (const auto& data : allData) {
Chenjie Yua7259ab2017-12-10 08:31:05 -0800268 onMatchedLogEventLocked(0, *data);
Yangster1d4d6862017-10-31 12:58:51 -0700269 }
Yangster1d4d6862017-10-31 12:58:51 -0700270}
271
Yangster-mac93694462018-01-22 20:49:31 -0800272bool GaugeMetricProducer::hitGuardRailLocked(const MetricDimensionKey& newKey) {
Yao Chenb3561512017-11-21 18:07:17 -0800273 if (mCurrentSlicedBucket->find(newKey) != mCurrentSlicedBucket->end()) {
274 return false;
275 }
276 // 1. Report the tuple count if the tuple count > soft limit
277 if (mCurrentSlicedBucket->size() > StatsdStats::kDimensionKeySizeSoftLimit - 1) {
278 size_t newTupleCount = mCurrentSlicedBucket->size() + 1;
Yangster-mac94e197c2018-01-02 16:03:03 -0800279 StatsdStats::getInstance().noteMetricDimensionSize(mConfigKey, mMetricId, newTupleCount);
Yao Chenb3561512017-11-21 18:07:17 -0800280 // 2. Don't add more tuples, we are above the allowed threshold. Drop the data.
281 if (newTupleCount > StatsdStats::kDimensionKeySizeHardLimit) {
Yangster-mac94e197c2018-01-02 16:03:03 -0800282 ALOGE("GaugeMetric %lld dropping data for dimension key %s",
283 (long long)mMetricId, newKey.c_str());
Yao Chenb3561512017-11-21 18:07:17 -0800284 return true;
285 }
286 }
287
288 return false;
289}
290
Yangsterf2bee6f2017-11-29 12:01:05 -0800291void GaugeMetricProducer::onMatchedLogEventInternalLocked(
Yangster-mac93694462018-01-22 20:49:31 -0800292 const size_t matcherIndex, const MetricDimensionKey& eventKey,
Yangster-mac20877162017-12-22 17:19:39 -0800293 const ConditionKey& conditionKey, bool condition,
Chenjie Yua7259ab2017-12-10 08:31:05 -0800294 const LogEvent& event) {
Yangster1d4d6862017-10-31 12:58:51 -0700295 if (condition == false) {
296 return;
297 }
Yao Chen6a8c7992017-11-29 20:02:07 +0000298 uint64_t eventTimeNs = event.GetTimestampNs();
Yangster1d4d6862017-10-31 12:58:51 -0700299 if (eventTimeNs < mCurrentBucketStartTimeNs) {
300 VLOG("Skip event due to late arrival: %lld vs %lld", (long long)eventTimeNs,
301 (long long)mCurrentBucketStartTimeNs);
302 return;
303 }
Chenjie Yud9dfda72017-12-11 17:41:20 -0800304 flushIfNeededLocked(eventTimeNs);
Yao Chen6a8c7992017-11-29 20:02:07 +0000305
Yangster-mac34ea1102018-01-29 12:40:55 -0800306 // When gauge metric wants to randomly sample the output atom, we just simply use the first
307 // gauge in the given bucket.
308 if (mCurrentSlicedBucket->find(eventKey) != mCurrentSlicedBucket->end() &&
309 mSamplingType == GaugeMetric::RANDOM_ONE_SAMPLE) {
Yangster1d4d6862017-10-31 12:58:51 -0700310 return;
311 }
Chenjie Yud9dfda72017-12-11 17:41:20 -0800312 if (hitGuardRailLocked(eventKey)) {
313 return;
Yao Chen6a8c7992017-11-29 20:02:07 +0000314 }
Yangster-mac34ea1102018-01-29 12:40:55 -0800315 GaugeAtom gaugeAtom;
316 gaugeAtom.mFields = getGaugeFields(event);
317 gaugeAtom.mTimestamps = eventTimeNs;
318 (*mCurrentSlicedBucket)[eventKey].push_back(gaugeAtom);
Chenjie Yud9dfda72017-12-11 17:41:20 -0800319 // Anomaly detection on gauge metric only works when there is one numeric
320 // field specified.
321 if (mAnomalyTrackers.size() > 0) {
Yangster-mac34ea1102018-01-29 12:40:55 -0800322 if (gaugeAtom.mFields->size() == 1) {
323 const DimensionsValue& dimensionsValue = gaugeAtom.mFields->begin()->second;
Chenjie Yud9dfda72017-12-11 17:41:20 -0800324 long gaugeVal = 0;
Yangster-mac20877162017-12-22 17:19:39 -0800325 if (dimensionsValue.has_value_int()) {
326 gaugeVal = (long)dimensionsValue.value_int();
327 } else if (dimensionsValue.has_value_long()) {
328 gaugeVal = dimensionsValue.value_long();
Chenjie Yud9dfda72017-12-11 17:41:20 -0800329 }
330 for (auto& tracker : mAnomalyTrackers) {
331 tracker->detectAndDeclareAnomaly(eventTimeNs, mCurrentBucketNum, eventKey,
332 gaugeVal);
333 }
334 }
335 }
336}
337
338void GaugeMetricProducer::updateCurrentSlicedBucketForAnomaly() {
Chenjie Yud9dfda72017-12-11 17:41:20 -0800339 status_t err = NO_ERROR;
340 for (const auto& slice : *mCurrentSlicedBucket) {
Yangster-mac34ea1102018-01-29 12:40:55 -0800341 if (slice.second.empty() || slice.second.front().mFields->empty()) {
342 continue;
343 }
344 const DimensionsValue& dimensionsValue = slice.second.front().mFields->begin()->second;
Chenjie Yud9dfda72017-12-11 17:41:20 -0800345 long gaugeVal = 0;
Yangster-mac20877162017-12-22 17:19:39 -0800346 if (dimensionsValue.has_value_int()) {
347 gaugeVal = (long)dimensionsValue.value_int();
348 } else if (dimensionsValue.has_value_long()) {
349 gaugeVal = dimensionsValue.value_long();
Chenjie Yud9dfda72017-12-11 17:41:20 -0800350 }
351 (*mCurrentSlicedBucketForAnomaly)[slice.first] = gaugeVal;
Yangster1d4d6862017-10-31 12:58:51 -0700352 }
353}
354
355// When a new matched event comes in, we check if event falls into the current
356// bucket. If not, flush the old counter to past buckets and initialize the new
357// bucket.
358// if data is pushed, onMatchedLogEvent will only be called through onConditionChanged() inside
359// the GaugeMetricProducer while holding the lock.
Yangsterf2bee6f2017-11-29 12:01:05 -0800360void GaugeMetricProducer::flushIfNeededLocked(const uint64_t& eventTimeNs) {
David Chen27785a82018-01-19 17:06:45 -0800361 uint64_t currentBucketEndTimeNs = getCurrentBucketEndTimeNs();
362
363 if (eventTimeNs < currentBucketEndTimeNs) {
Chenjie Yud9dfda72017-12-11 17:41:20 -0800364 VLOG("eventTime is %lld, less than next bucket start time %lld", (long long)eventTimeNs,
365 (long long)(mCurrentBucketStartTimeNs + mBucketSizeNs));
Yangster1d4d6862017-10-31 12:58:51 -0700366 return;
367 }
368
David Chen27785a82018-01-19 17:06:45 -0800369 flushCurrentBucketLocked(eventTimeNs);
370
371 // Adjusts the bucket start and end times.
372 int64_t numBucketsForward = 1 + (eventTimeNs - currentBucketEndTimeNs) / mBucketSizeNs;
373 mCurrentBucketStartTimeNs = currentBucketEndTimeNs + (numBucketsForward - 1) * mBucketSizeNs;
374 mCurrentBucketNum += numBucketsForward;
375 VLOG("metric %lld: new bucket start time: %lld", (long long)mMetricId,
376 (long long)mCurrentBucketStartTimeNs);
377}
378
379void GaugeMetricProducer::flushCurrentBucketLocked(const uint64_t& eventTimeNs) {
380 uint64_t fullBucketEndTimeNs = getCurrentBucketEndTimeNs();
381
yro2b0f8862017-11-06 14:27:31 -0800382 GaugeBucket info;
383 info.mBucketStartNs = mCurrentBucketStartTimeNs;
David Chen27785a82018-01-19 17:06:45 -0800384 if (eventTimeNs < fullBucketEndTimeNs) {
385 info.mBucketEndNs = eventTimeNs;
386 } else {
387 info.mBucketEndNs = fullBucketEndTimeNs;
388 }
Yangster-mace2cd6d52017-11-09 20:38:30 -0800389 info.mBucketNum = mCurrentBucketNum;
Yangster1d4d6862017-10-31 12:58:51 -0700390
Yangster-mace2cd6d52017-11-09 20:38:30 -0800391 for (const auto& slice : *mCurrentSlicedBucket) {
Yangster-mac34ea1102018-01-29 12:40:55 -0800392 info.mGaugeAtoms = slice.second;
Yangster1d4d6862017-10-31 12:58:51 -0700393 auto& bucketList = mPastBuckets[slice.first];
394 bucketList.push_back(info);
David Chen27785a82018-01-19 17:06:45 -0800395 VLOG("gauge metric %lld, dump key value: %s", (long long)mMetricId, slice.first.c_str());
Yangster1d4d6862017-10-31 12:58:51 -0700396 }
Yangster1d4d6862017-10-31 12:58:51 -0700397
David Chen27785a82018-01-19 17:06:45 -0800398 // If we have anomaly trackers, we need to update the partial bucket values.
Chenjie Yud9dfda72017-12-11 17:41:20 -0800399 if (mAnomalyTrackers.size() > 0) {
400 updateCurrentSlicedBucketForAnomaly();
David Chen27785a82018-01-19 17:06:45 -0800401
402 if (eventTimeNs > fullBucketEndTimeNs) {
403 // This is known to be a full bucket, so send this data to the anomaly tracker.
404 for (auto& tracker : mAnomalyTrackers) {
405 tracker->addPastBucket(mCurrentSlicedBucketForAnomaly, mCurrentBucketNum);
406 }
407 mCurrentSlicedBucketForAnomaly = std::make_shared<DimToValMap>();
Chenjie Yud9dfda72017-12-11 17:41:20 -0800408 }
Yangster-mace2cd6d52017-11-09 20:38:30 -0800409 }
410
Yangster-mac34ea1102018-01-29 12:40:55 -0800411 mCurrentSlicedBucket = std::make_shared<DimToGaugeAtomsMap>();
Yangster1d4d6862017-10-31 12:58:51 -0700412}
413
Yangsterf2bee6f2017-11-29 12:01:05 -0800414size_t GaugeMetricProducer::byteSizeLocked() const {
Yangster-mace2cd6d52017-11-09 20:38:30 -0800415 size_t totalSize = 0;
416 for (const auto& pair : mPastBuckets) {
417 totalSize += pair.second.size() * kBucketSize;
418 }
419 return totalSize;
yro2b0f8862017-11-06 14:27:31 -0800420}
421
Yangster1d4d6862017-10-31 12:58:51 -0700422} // namespace statsd
423} // namespace os
424} // namespace android