blob: 6886f7c2e87a975eb3f43aded64e90fb442ff45a [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
Chenjie Yuc5875052018-03-09 10:13:11 -080020#include "../guardrail/StatsdStats.h"
Yangster1d4d6862017-10-31 12:58:51 -070021#include "GaugeMetricProducer.h"
Chenjie Yuc5875052018-03-09 10:13:11 -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;
Yangster-mac3fa5d7f2018-03-10 21:50:27 -080059const int FIELD_ID_WALL_CLOCK_ATOM_TIMESTAMP = 5;
yro2b0f8862017-11-06 14:27:31 -080060
Yao Chenb3561512017-11-21 18:07:17 -080061GaugeMetricProducer::GaugeMetricProducer(const ConfigKey& key, const GaugeMetric& metric,
62 const int conditionIndex,
Chenjie Yuc5875052018-03-09 10:13:11 -080063 const sp<ConditionWizard>& wizard, const int pullTagId,
Yangster-mac15f6bbc2018-04-08 11:52:26 -070064 const int64_t timeBaseNs, const int64_t startTimeNs,
Chenjie Yud9dfda72017-12-11 17:41:20 -080065 shared_ptr<StatsPullerManager> statsPullerManager)
Yangster-mac15f6bbc2018-04-08 11:52:26 -070066 : MetricProducer(metric.id(), key, timeBaseNs, conditionIndex, wizard),
Chenjie Yud9dfda72017-12-11 17:41:20 -080067 mStatsPullerManager(statsPullerManager),
Chenjie Yuc5875052018-03-09 10:13:11 -080068 mPullTagId(pullTagId),
69 mDimensionSoftLimit(StatsdStats::kAtomDimensionKeySizeLimitMap.find(pullTagId) !=
70 StatsdStats::kAtomDimensionKeySizeLimitMap.end()
71 ? StatsdStats::kAtomDimensionKeySizeLimitMap.at(pullTagId).first
72 : StatsdStats::kDimensionKeySizeSoftLimit),
73 mDimensionHardLimit(StatsdStats::kAtomDimensionKeySizeLimitMap.find(pullTagId) !=
74 StatsdStats::kAtomDimensionKeySizeLimitMap.end()
75 ? StatsdStats::kAtomDimensionKeySizeLimitMap.at(pullTagId).second
76 : StatsdStats::kDimensionKeySizeHardLimit) {
Yangster-mac34ea1102018-01-29 12:40:55 -080077 mCurrentSlicedBucket = std::make_shared<DimToGaugeAtomsMap>();
Yangster-mac20877162017-12-22 17:19:39 -080078 mCurrentSlicedBucketForAnomaly = std::make_shared<DimToValMap>();
Yangster-macb8144812018-01-04 10:56:23 -080079 int64_t bucketSizeMills = 0;
80 if (metric.has_bucket()) {
yro59cc24d2018-02-13 20:17:32 -080081 bucketSizeMills = TimeUnitToBucketSizeInMillisGuardrailed(key.GetUid(), metric.bucket());
Yangster1d4d6862017-10-31 12:58:51 -070082 } else {
Yangster-macb8144812018-01-04 10:56:23 -080083 bucketSizeMills = TimeUnitToBucketSizeInMillis(ONE_HOUR);
Yangster1d4d6862017-10-31 12:58:51 -070084 }
Yangster-macb8144812018-01-04 10:56:23 -080085 mBucketSizeNs = bucketSizeMills * 1000000;
Yangster1d4d6862017-10-31 12:58:51 -070086
Yangster-mac34ea1102018-01-29 12:40:55 -080087 mSamplingType = metric.sampling_type();
Yao Chen8a8d16c2018-02-08 14:50:40 -080088 if (!metric.gauge_fields_filter().include_all()) {
89 translateFieldMatcher(metric.gauge_fields_filter().fields(), &mFieldMatchers);
90 }
Chenjie Yud9dfda72017-12-11 17:41:20 -080091
Yangster1d4d6862017-10-31 12:58:51 -070092 // TODO: use UidMap if uid->pkg_name is required
Yao Chen8a8d16c2018-02-08 14:50:40 -080093 if (metric.has_dimensions_in_what()) {
94 translateFieldMatcher(metric.dimensions_in_what(), &mDimensionsInWhat);
Yangster13fb7e42018-03-07 17:30:49 -080095 mContainANYPositionInDimensionsInWhat = HasPositionANY(metric.dimensions_in_what());
Yao Chen8a8d16c2018-02-08 14:50:40 -080096 }
97
98 if (metric.has_dimensions_in_condition()) {
99 translateFieldMatcher(metric.dimensions_in_condition(), &mDimensionsInCondition);
100 }
Yangster1d4d6862017-10-31 12:58:51 -0700101
102 if (metric.links().size() > 0) {
Yao Chen8a8d16c2018-02-08 14:50:40 -0800103 for (const auto& link : metric.links()) {
104 Metric2Condition mc;
105 mc.conditionId = link.condition();
106 translateFieldMatcher(link.fields_in_what(), &mc.metricFields);
107 translateFieldMatcher(link.fields_in_condition(), &mc.conditionFields);
108 mMetric2ConditionLinks.push_back(mc);
109 }
Yangster1d4d6862017-10-31 12:58:51 -0700110 }
Yao Chen8a8d16c2018-02-08 14:50:40 -0800111 mConditionSliced = (metric.links().size() > 0) || (mDimensionsInCondition.size() > 0);
Yangster1d4d6862017-10-31 12:58:51 -0700112
Yangster-mac15f6bbc2018-04-08 11:52:26 -0700113 flushIfNeededLocked(startTimeNs);
Yangster1d4d6862017-10-31 12:58:51 -0700114 // Kicks off the puller immediately.
Yangster-mac34ea1102018-01-29 12:40:55 -0800115 if (mPullTagId != -1 && mSamplingType == GaugeMetric::RANDOM_ONE_SAMPLE) {
Chenjie Yu1a0a9412018-03-28 10:07:22 -0700116 mStatsPullerManager->RegisterReceiver(
Yangster-mac15f6bbc2018-04-08 11:52:26 -0700117 mPullTagId, this, getCurrentBucketEndTimeNs(), mBucketSizeNs);
Yangster1d4d6862017-10-31 12:58:51 -0700118 }
119
Yao Chen427d3722018-03-22 15:21:52 -0700120 VLOG("Gauge metric %lld created. bucket size %lld start_time: %lld sliced %d",
Yangster-mac15f6bbc2018-04-08 11:52:26 -0700121 (long long)metric.id(), (long long)mBucketSizeNs, (long long)mTimeBaseNs,
Yao Chen427d3722018-03-22 15:21:52 -0700122 mConditionSliced);
Yangster1d4d6862017-10-31 12:58:51 -0700123}
124
Chenjie Yud9dfda72017-12-11 17:41:20 -0800125// for testing
126GaugeMetricProducer::GaugeMetricProducer(const ConfigKey& key, const GaugeMetric& metric,
127 const int conditionIndex,
128 const sp<ConditionWizard>& wizard, const int pullTagId,
Yangster-mac15f6bbc2018-04-08 11:52:26 -0700129 const int64_t timeBaseNs, const int64_t startTimeNs)
130 : GaugeMetricProducer(key, metric, conditionIndex, wizard, pullTagId, timeBaseNs, startTimeNs,
Chenjie Yud9dfda72017-12-11 17:41:20 -0800131 make_shared<StatsPullerManager>()) {
132}
133
Yangster1d4d6862017-10-31 12:58:51 -0700134GaugeMetricProducer::~GaugeMetricProducer() {
135 VLOG("~GaugeMetricProducer() called");
Yangster-mac15f6bbc2018-04-08 11:52:26 -0700136 if (mPullTagId != -1 && mSamplingType == GaugeMetric::RANDOM_ONE_SAMPLE) {
Chenjie Yud9dfda72017-12-11 17:41:20 -0800137 mStatsPullerManager->UnRegisterReceiver(mPullTagId, this);
Chenjie Yu032fefc2017-12-01 23:30:59 -0800138 }
Yangster1d4d6862017-10-31 12:58:51 -0700139}
140
Yangster-maca78d0082018-03-12 12:02:56 -0700141void GaugeMetricProducer::dumpStatesLocked(FILE* out, bool verbose) const {
142 if (mCurrentSlicedBucket == nullptr ||
143 mCurrentSlicedBucket->size() == 0) {
144 return;
145 }
146
147 fprintf(out, "GaugeMetric %lld dimension size %lu\n", (long long)mMetricId,
148 (unsigned long)mCurrentSlicedBucket->size());
149 if (verbose) {
150 for (const auto& it : *mCurrentSlicedBucket) {
151 fprintf(out, "\t(what)%s\t(condition)%s %d atoms\n",
152 it.first.getDimensionKeyInWhat().toString().c_str(),
153 it.first.getDimensionKeyInCondition().toString().c_str(),
154 (int)it.second.size());
155 }
156 }
157}
158
Yangster-macb142cc82018-03-30 15:22:08 -0700159void GaugeMetricProducer::onDumpReportLocked(const int64_t dumpTimeNs,
Yangster-mace68f3a52018-04-04 00:01:43 -0700160 const bool include_current_partial_bucket,
Yao Chen288c6002017-12-12 13:43:18 -0800161 ProtoOutputStream* protoOutput) {
Yao Chen427d3722018-03-22 15:21:52 -0700162 VLOG("Gauge metric %lld report now...", (long long)mMetricId);
Yangster-mace68f3a52018-04-04 00:01:43 -0700163 if (include_current_partial_bucket) {
164 flushLocked(dumpTimeNs);
165 } else {
166 flushIfNeededLocked(dumpTimeNs);
167 }
Yao Chen6a8c7992017-11-29 20:02:07 +0000168
Yao Chen288c6002017-12-12 13:43:18 -0800169 flushIfNeededLocked(dumpTimeNs);
Yangster-mac635b4b32018-01-23 20:17:35 -0800170 if (mPastBuckets.empty()) {
171 return;
172 }
Yao Chen288c6002017-12-12 13:43:18 -0800173
Yangster-mac94e197c2018-01-02 16:03:03 -0800174 protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_ID, (long long)mMetricId);
Yi Jin5ee07872018-03-05 18:18:27 -0800175 uint64_t protoToken = protoOutput->start(FIELD_TYPE_MESSAGE | FIELD_ID_GAUGE_METRICS);
Yao Chen6a8c7992017-11-29 20:02:07 +0000176
Yangster1d4d6862017-10-31 12:58:51 -0700177 for (const auto& pair : mPastBuckets) {
Yangster-mac93694462018-01-22 20:49:31 -0800178 const MetricDimensionKey& dimensionKey = pair.first;
Yangster1d4d6862017-10-31 12:58:51 -0700179
Yao Chen427d3722018-03-22 15:21:52 -0700180 VLOG("Gauge dimension key %s", dimensionKey.toString().c_str());
Yi Jin5ee07872018-03-05 18:18:27 -0800181 uint64_t wrapperToken =
Yao Chen288c6002017-12-12 13:43:18 -0800182 protoOutput->start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | FIELD_ID_DATA);
yro2b0f8862017-11-06 14:27:31 -0800183
Yangster-mac20877162017-12-22 17:19:39 -0800184 // First fill dimension.
Yi Jin5ee07872018-03-05 18:18:27 -0800185 uint64_t dimensionToken = protoOutput->start(
Yangster-mac468ff042018-01-17 12:26:34 -0800186 FIELD_TYPE_MESSAGE | FIELD_ID_DIMENSION_IN_WHAT);
Yao Chen8a8d16c2018-02-08 14:50:40 -0800187 writeDimensionToProto(dimensionKey.getDimensionKeyInWhat(), protoOutput);
Yangster-mac20877162017-12-22 17:19:39 -0800188 protoOutput->end(dimensionToken);
yro2b0f8862017-11-06 14:27:31 -0800189
Yangster-mac93694462018-01-22 20:49:31 -0800190 if (dimensionKey.hasDimensionKeyInCondition()) {
Yi Jin5ee07872018-03-05 18:18:27 -0800191 uint64_t dimensionInConditionToken = protoOutput->start(
Yangster-mac93694462018-01-22 20:49:31 -0800192 FIELD_TYPE_MESSAGE | FIELD_ID_DIMENSION_IN_CONDITION);
Yao Chen8a8d16c2018-02-08 14:50:40 -0800193 writeDimensionToProto(dimensionKey.getDimensionKeyInCondition(), protoOutput);
Yangster-mac93694462018-01-22 20:49:31 -0800194 protoOutput->end(dimensionInConditionToken);
195 }
196
yro2b0f8862017-11-06 14:27:31 -0800197 // Then fill bucket_info (GaugeBucketInfo).
198 for (const auto& bucket : pair.second) {
Yi Jin5ee07872018-03-05 18:18:27 -0800199 uint64_t bucketInfoToken = protoOutput->start(
Yao Chen288c6002017-12-12 13:43:18 -0800200 FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | FIELD_ID_BUCKET_INFO);
Yangster-mac330af582018-02-08 15:24:38 -0800201 protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_START_BUCKET_ELAPSED_NANOS,
Yao Chen288c6002017-12-12 13:43:18 -0800202 (long long)bucket.mBucketStartNs);
Yangster-mac330af582018-02-08 15:24:38 -0800203 protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_END_BUCKET_ELAPSED_NANOS,
Yao Chen288c6002017-12-12 13:43:18 -0800204 (long long)bucket.mBucketEndNs);
Yangster-mac34ea1102018-01-29 12:40:55 -0800205
206 if (!bucket.mGaugeAtoms.empty()) {
Yangster-mac34ea1102018-01-29 12:40:55 -0800207 for (const auto& atom : bucket.mGaugeAtoms) {
Yangster-mac3fa5d7f2018-03-10 21:50:27 -0800208 uint64_t atomsToken =
209 protoOutput->start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED |
210 FIELD_ID_ATOM);
Yao Chen8a8d16c2018-02-08 14:50:40 -0800211 writeFieldValueTreeToStream(mTagId, *(atom.mFields), protoOutput);
Yangster-mac3fa5d7f2018-03-10 21:50:27 -0800212 protoOutput->end(atomsToken);
Yangster-mac34ea1102018-01-29 12:40:55 -0800213 }
Yangster-mac3fa5d7f2018-03-10 21:50:27 -0800214 const bool truncateTimestamp =
Yao Chenc40a19d2018-03-15 16:48:25 -0700215 android::util::AtomsInfo::kNotTruncatingTimestampAtomWhiteList.find(
216 mTagId) ==
217 android::util::AtomsInfo::kNotTruncatingTimestampAtomWhiteList.end();
Yangster-mac34ea1102018-01-29 12:40:55 -0800218 for (const auto& atom : bucket.mGaugeAtoms) {
Yangster-mac15f6bbc2018-04-08 11:52:26 -0700219 const int64_t elapsedTimestampNs = truncateTimestamp ?
220 truncateTimestampNsToFiveMinutes(atom.mElapsedTimestamps) :
221 atom.mElapsedTimestamps;
222 const int64_t wallClockNs = truncateTimestamp ?
223 truncateTimestampNsToFiveMinutes(atom.mWallClockTimestampNs) :
224 atom.mWallClockTimestampNs;
Yangster-mac330af582018-02-08 15:24:38 -0800225 protoOutput->write(
226 FIELD_TYPE_INT64 | FIELD_COUNT_REPEATED | FIELD_ID_ELAPSED_ATOM_TIMESTAMP,
Yangster-mac15f6bbc2018-04-08 11:52:26 -0700227 (long long)elapsedTimestampNs);
Yangster-mac3fa5d7f2018-03-10 21:50:27 -0800228 protoOutput->write(
229 FIELD_TYPE_INT64 | FIELD_COUNT_REPEATED |
230 FIELD_ID_WALL_CLOCK_ATOM_TIMESTAMP,
Yangster-mac15f6bbc2018-04-08 11:52:26 -0700231 (long long)wallClockNs);
Yangster-mac34ea1102018-01-29 12:40:55 -0800232 }
233 }
Yao Chen288c6002017-12-12 13:43:18 -0800234 protoOutput->end(bucketInfoToken);
Yao Chen427d3722018-03-22 15:21:52 -0700235 VLOG("Gauge \t bucket [%lld - %lld] includes %d atoms.",
236 (long long)bucket.mBucketStartNs, (long long)bucket.mBucketEndNs,
237 (int)bucket.mGaugeAtoms.size());
yro2b0f8862017-11-06 14:27:31 -0800238 }
Yao Chen288c6002017-12-12 13:43:18 -0800239 protoOutput->end(wrapperToken);
Yangster1d4d6862017-10-31 12:58:51 -0700240 }
Yao Chen288c6002017-12-12 13:43:18 -0800241 protoOutput->end(protoToken);
yro2b0f8862017-11-06 14:27:31 -0800242
Yao Chen6a8c7992017-11-29 20:02:07 +0000243 mPastBuckets.clear();
yro2b0f8862017-11-06 14:27:31 -0800244 // TODO: Clear mDimensionKeyMap once the report is dumped.
Yangster1d4d6862017-10-31 12:58:51 -0700245}
246
Yangster-mac15f6bbc2018-04-08 11:52:26 -0700247void GaugeMetricProducer::pullLocked(const int64_t timestampNs) {
Yangster-mac34ea1102018-01-29 12:40:55 -0800248 bool triggerPuller = false;
249 switch(mSamplingType) {
250 // When the metric wants to do random sampling and there is already one gauge atom for the
251 // current bucket, do not do it again.
252 case GaugeMetric::RANDOM_ONE_SAMPLE: {
253 triggerPuller = mCondition && mCurrentSlicedBucket->empty();
254 break;
255 }
256 case GaugeMetric::ALL_CONDITION_CHANGES: {
257 triggerPuller = true;
258 break;
259 }
260 default:
261 break;
262 }
263 if (!triggerPuller) {
Yao Chen6a8c7992017-11-29 20:02:07 +0000264 return;
265 }
Yangster-mac34ea1102018-01-29 12:40:55 -0800266
Yao Chen6a8c7992017-11-29 20:02:07 +0000267 vector<std::shared_ptr<LogEvent>> allData;
Yangster-mac15f6bbc2018-04-08 11:52:26 -0700268 if (!mStatsPullerManager->Pull(mPullTagId, timestampNs, &allData)) {
Yao Chen427d3722018-03-22 15:21:52 -0700269 ALOGE("Gauge Stats puller failed for tag: %d", mPullTagId);
Yao Chen6a8c7992017-11-29 20:02:07 +0000270 return;
271 }
Yao Chen427d3722018-03-22 15:21:52 -0700272
Yangster1d4d6862017-10-31 12:58:51 -0700273 for (const auto& data : allData) {
Chenjie Yua7259ab2017-12-10 08:31:05 -0800274 onMatchedLogEventLocked(0, *data);
Yangster1d4d6862017-10-31 12:58:51 -0700275 }
Yangster1d4d6862017-10-31 12:58:51 -0700276}
277
Yao Chen427d3722018-03-22 15:21:52 -0700278void GaugeMetricProducer::onConditionChangedLocked(const bool conditionMet,
Yangster-mac15f6bbc2018-04-08 11:52:26 -0700279 const int64_t eventTimeNs) {
Yao Chen427d3722018-03-22 15:21:52 -0700280 VLOG("GaugeMetric %lld onConditionChanged", (long long)mMetricId);
Yangster-mac15f6bbc2018-04-08 11:52:26 -0700281 flushIfNeededLocked(eventTimeNs);
Yao Chen427d3722018-03-22 15:21:52 -0700282 mCondition = conditionMet;
283
Yangster-mac15f6bbc2018-04-08 11:52:26 -0700284 if (mPullTagId != -1 && mCondition) {
285 pullLocked(eventTimeNs);
Yao Chen427d3722018-03-22 15:21:52 -0700286 } // else: Push mode. No need to proactively pull the gauge data.
287}
288
289void GaugeMetricProducer::onSlicedConditionMayChangeLocked(bool overallCondition,
Yangster-mac15f6bbc2018-04-08 11:52:26 -0700290 const int64_t eventTimeNs) {
Yao Chen427d3722018-03-22 15:21:52 -0700291 VLOG("GaugeMetric %lld onSlicedConditionMayChange overall condition %d", (long long)mMetricId,
292 overallCondition);
Yangster-mac15f6bbc2018-04-08 11:52:26 -0700293 flushIfNeededLocked(eventTimeNs);
Yao Chen427d3722018-03-22 15:21:52 -0700294 // If the condition is sliced, mCondition is true if any of the dimensions is true. And we will
295 // pull for every dimension.
296 mCondition = overallCondition;
297 if (mPullTagId != -1) {
Yangster-mac15f6bbc2018-04-08 11:52:26 -0700298 pullLocked(eventTimeNs);
Yao Chen427d3722018-03-22 15:21:52 -0700299 } // else: Push mode. No need to proactively pull the gauge data.
Yangster1d4d6862017-10-31 12:58:51 -0700300}
301
Yao Chen8a8d16c2018-02-08 14:50:40 -0800302std::shared_ptr<vector<FieldValue>> GaugeMetricProducer::getGaugeFields(const LogEvent& event) {
303 if (mFieldMatchers.size() > 0) {
304 std::shared_ptr<vector<FieldValue>> gaugeFields = std::make_shared<vector<FieldValue>>();
305 filterGaugeValues(mFieldMatchers, event.getValues(), gaugeFields.get());
306 return gaugeFields;
307 } else {
308 return std::make_shared<vector<FieldValue>>(event.getValues());
Yangster1d4d6862017-10-31 12:58:51 -0700309 }
310}
311
312void GaugeMetricProducer::onDataPulled(const std::vector<std::shared_ptr<LogEvent>>& allData) {
Yangsterf2bee6f2017-11-29 12:01:05 -0800313 std::lock_guard<std::mutex> lock(mMutex);
Chenjie Yud9dfda72017-12-11 17:41:20 -0800314 if (allData.size() == 0) {
315 return;
316 }
Yangster1d4d6862017-10-31 12:58:51 -0700317 for (const auto& data : allData) {
Chenjie Yua7259ab2017-12-10 08:31:05 -0800318 onMatchedLogEventLocked(0, *data);
Yangster1d4d6862017-10-31 12:58:51 -0700319 }
Yangster1d4d6862017-10-31 12:58:51 -0700320}
321
Yangster-mac93694462018-01-22 20:49:31 -0800322bool GaugeMetricProducer::hitGuardRailLocked(const MetricDimensionKey& newKey) {
Yao Chenb3561512017-11-21 18:07:17 -0800323 if (mCurrentSlicedBucket->find(newKey) != mCurrentSlicedBucket->end()) {
324 return false;
325 }
326 // 1. Report the tuple count if the tuple count > soft limit
Chenjie Yuc5875052018-03-09 10:13:11 -0800327 if (mCurrentSlicedBucket->size() > mDimensionSoftLimit - 1) {
Yao Chenb3561512017-11-21 18:07:17 -0800328 size_t newTupleCount = mCurrentSlicedBucket->size() + 1;
Yangster-mac94e197c2018-01-02 16:03:03 -0800329 StatsdStats::getInstance().noteMetricDimensionSize(mConfigKey, mMetricId, newTupleCount);
Yao Chenb3561512017-11-21 18:07:17 -0800330 // 2. Don't add more tuples, we are above the allowed threshold. Drop the data.
Chenjie Yuc5875052018-03-09 10:13:11 -0800331 if (newTupleCount > mDimensionHardLimit) {
Yangster-mac94e197c2018-01-02 16:03:03 -0800332 ALOGE("GaugeMetric %lld dropping data for dimension key %s",
Yangster13fb7e42018-03-07 17:30:49 -0800333 (long long)mMetricId, newKey.toString().c_str());
Yao Chenb3561512017-11-21 18:07:17 -0800334 return true;
335 }
336 }
337
338 return false;
339}
340
Yangsterf2bee6f2017-11-29 12:01:05 -0800341void GaugeMetricProducer::onMatchedLogEventInternalLocked(
Yangster-mac93694462018-01-22 20:49:31 -0800342 const size_t matcherIndex, const MetricDimensionKey& eventKey,
Yangster-mac20877162017-12-22 17:19:39 -0800343 const ConditionKey& conditionKey, bool condition,
Chenjie Yua7259ab2017-12-10 08:31:05 -0800344 const LogEvent& event) {
Yangster1d4d6862017-10-31 12:58:51 -0700345 if (condition == false) {
346 return;
347 }
Yangster-macb142cc82018-03-30 15:22:08 -0700348 int64_t eventTimeNs = event.GetElapsedTimestampNs();
Yao Chen8a8d16c2018-02-08 14:50:40 -0800349 mTagId = event.GetTagId();
Yangster1d4d6862017-10-31 12:58:51 -0700350 if (eventTimeNs < mCurrentBucketStartTimeNs) {
Yao Chen427d3722018-03-22 15:21:52 -0700351 VLOG("Gauge Skip event due to late arrival: %lld vs %lld", (long long)eventTimeNs,
Yangster1d4d6862017-10-31 12:58:51 -0700352 (long long)mCurrentBucketStartTimeNs);
353 return;
354 }
Chenjie Yud9dfda72017-12-11 17:41:20 -0800355 flushIfNeededLocked(eventTimeNs);
Yao Chen6a8c7992017-11-29 20:02:07 +0000356
Yangster-mac34ea1102018-01-29 12:40:55 -0800357 // When gauge metric wants to randomly sample the output atom, we just simply use the first
358 // gauge in the given bucket.
359 if (mCurrentSlicedBucket->find(eventKey) != mCurrentSlicedBucket->end() &&
360 mSamplingType == GaugeMetric::RANDOM_ONE_SAMPLE) {
Yangster1d4d6862017-10-31 12:58:51 -0700361 return;
362 }
Chenjie Yud9dfda72017-12-11 17:41:20 -0800363 if (hitGuardRailLocked(eventKey)) {
364 return;
Yao Chen6a8c7992017-11-29 20:02:07 +0000365 }
Yangster-mac15f6bbc2018-04-08 11:52:26 -0700366 GaugeAtom gaugeAtom(getGaugeFields(event), eventTimeNs, getWallClockNs());
Yangster-mac34ea1102018-01-29 12:40:55 -0800367 (*mCurrentSlicedBucket)[eventKey].push_back(gaugeAtom);
Chenjie Yud9dfda72017-12-11 17:41:20 -0800368 // Anomaly detection on gauge metric only works when there is one numeric
369 // field specified.
370 if (mAnomalyTrackers.size() > 0) {
Yangster-mac34ea1102018-01-29 12:40:55 -0800371 if (gaugeAtom.mFields->size() == 1) {
Yao Chen8a8d16c2018-02-08 14:50:40 -0800372 const Value& value = gaugeAtom.mFields->begin()->mValue;
Chenjie Yud9dfda72017-12-11 17:41:20 -0800373 long gaugeVal = 0;
Yao Chen8a8d16c2018-02-08 14:50:40 -0800374 if (value.getType() == INT) {
375 gaugeVal = (long)value.int_value;
376 } else if (value.getType() == LONG) {
377 gaugeVal = value.long_value;
Chenjie Yud9dfda72017-12-11 17:41:20 -0800378 }
379 for (auto& tracker : mAnomalyTrackers) {
380 tracker->detectAndDeclareAnomaly(eventTimeNs, mCurrentBucketNum, eventKey,
381 gaugeVal);
382 }
383 }
384 }
385}
386
387void GaugeMetricProducer::updateCurrentSlicedBucketForAnomaly() {
Chenjie Yud9dfda72017-12-11 17:41:20 -0800388 for (const auto& slice : *mCurrentSlicedBucket) {
Yao Chen8a8d16c2018-02-08 14:50:40 -0800389 if (slice.second.empty()) {
Yangster-mac34ea1102018-01-29 12:40:55 -0800390 continue;
391 }
Yao Chen8a8d16c2018-02-08 14:50:40 -0800392 const Value& value = slice.second.front().mFields->front().mValue;
Chenjie Yud9dfda72017-12-11 17:41:20 -0800393 long gaugeVal = 0;
Yao Chen8a8d16c2018-02-08 14:50:40 -0800394 if (value.getType() == INT) {
395 gaugeVal = (long)value.int_value;
396 } else if (value.getType() == LONG) {
397 gaugeVal = value.long_value;
Chenjie Yud9dfda72017-12-11 17:41:20 -0800398 }
399 (*mCurrentSlicedBucketForAnomaly)[slice.first] = gaugeVal;
Yangster1d4d6862017-10-31 12:58:51 -0700400 }
401}
402
Yangster-macb142cc82018-03-30 15:22:08 -0700403void GaugeMetricProducer::dropDataLocked(const int64_t dropTimeNs) {
Yao Chen06dba5d2018-01-26 13:38:16 -0800404 flushIfNeededLocked(dropTimeNs);
405 mPastBuckets.clear();
406}
407
Yangster1d4d6862017-10-31 12:58:51 -0700408// When a new matched event comes in, we check if event falls into the current
409// bucket. If not, flush the old counter to past buckets and initialize the new
410// bucket.
411// if data is pushed, onMatchedLogEvent will only be called through onConditionChanged() inside
412// the GaugeMetricProducer while holding the lock.
Yangster-macb142cc82018-03-30 15:22:08 -0700413void GaugeMetricProducer::flushIfNeededLocked(const int64_t& eventTimeNs) {
414 int64_t currentBucketEndTimeNs = getCurrentBucketEndTimeNs();
David Chen27785a82018-01-19 17:06:45 -0800415
416 if (eventTimeNs < currentBucketEndTimeNs) {
Yao Chen427d3722018-03-22 15:21:52 -0700417 VLOG("Gauge eventTime is %lld, less than next bucket start time %lld",
418 (long long)eventTimeNs, (long long)(mCurrentBucketStartTimeNs + mBucketSizeNs));
Yangster1d4d6862017-10-31 12:58:51 -0700419 return;
420 }
421
David Chen27785a82018-01-19 17:06:45 -0800422 flushCurrentBucketLocked(eventTimeNs);
423
424 // Adjusts the bucket start and end times.
425 int64_t numBucketsForward = 1 + (eventTimeNs - currentBucketEndTimeNs) / mBucketSizeNs;
426 mCurrentBucketStartTimeNs = currentBucketEndTimeNs + (numBucketsForward - 1) * mBucketSizeNs;
427 mCurrentBucketNum += numBucketsForward;
Yao Chen427d3722018-03-22 15:21:52 -0700428 VLOG("Gauge metric %lld: new bucket start time: %lld", (long long)mMetricId,
David Chen27785a82018-01-19 17:06:45 -0800429 (long long)mCurrentBucketStartTimeNs);
430}
431
Yangster-macb142cc82018-03-30 15:22:08 -0700432void GaugeMetricProducer::flushCurrentBucketLocked(const int64_t& eventTimeNs) {
433 int64_t fullBucketEndTimeNs = getCurrentBucketEndTimeNs();
David Chen27785a82018-01-19 17:06:45 -0800434
yro2b0f8862017-11-06 14:27:31 -0800435 GaugeBucket info;
436 info.mBucketStartNs = mCurrentBucketStartTimeNs;
David Chen27785a82018-01-19 17:06:45 -0800437 if (eventTimeNs < fullBucketEndTimeNs) {
438 info.mBucketEndNs = eventTimeNs;
439 } else {
440 info.mBucketEndNs = fullBucketEndTimeNs;
441 }
Yangster1d4d6862017-10-31 12:58:51 -0700442
Yangster-mace2cd6d52017-11-09 20:38:30 -0800443 for (const auto& slice : *mCurrentSlicedBucket) {
Yangster-mac34ea1102018-01-29 12:40:55 -0800444 info.mGaugeAtoms = slice.second;
Yangster1d4d6862017-10-31 12:58:51 -0700445 auto& bucketList = mPastBuckets[slice.first];
446 bucketList.push_back(info);
Yao Chen427d3722018-03-22 15:21:52 -0700447 VLOG("Gauge gauge metric %lld, dump key value: %s", (long long)mMetricId,
Yangster13fb7e42018-03-07 17:30:49 -0800448 slice.first.toString().c_str());
Yangster1d4d6862017-10-31 12:58:51 -0700449 }
Yangster1d4d6862017-10-31 12:58:51 -0700450
David Chen27785a82018-01-19 17:06:45 -0800451 // If we have anomaly trackers, we need to update the partial bucket values.
Chenjie Yud9dfda72017-12-11 17:41:20 -0800452 if (mAnomalyTrackers.size() > 0) {
453 updateCurrentSlicedBucketForAnomaly();
David Chen27785a82018-01-19 17:06:45 -0800454
455 if (eventTimeNs > fullBucketEndTimeNs) {
456 // This is known to be a full bucket, so send this data to the anomaly tracker.
457 for (auto& tracker : mAnomalyTrackers) {
458 tracker->addPastBucket(mCurrentSlicedBucketForAnomaly, mCurrentBucketNum);
459 }
460 mCurrentSlicedBucketForAnomaly = std::make_shared<DimToValMap>();
Chenjie Yud9dfda72017-12-11 17:41:20 -0800461 }
Yangster-mace2cd6d52017-11-09 20:38:30 -0800462 }
463
Yangster-mac34ea1102018-01-29 12:40:55 -0800464 mCurrentSlicedBucket = std::make_shared<DimToGaugeAtomsMap>();
Yangster1d4d6862017-10-31 12:58:51 -0700465}
466
Yangsterf2bee6f2017-11-29 12:01:05 -0800467size_t GaugeMetricProducer::byteSizeLocked() const {
Yangster-mace2cd6d52017-11-09 20:38:30 -0800468 size_t totalSize = 0;
469 for (const auto& pair : mPastBuckets) {
470 totalSize += pair.second.size() * kBucketSize;
471 }
472 return totalSize;
yro2b0f8862017-11-06 14:27:31 -0800473}
474
Yangster1d4d6862017-10-31 12:58:51 -0700475} // namespace statsd
476} // namespace os
477} // namespace android