Merge "1/ Use FieldMatcher to specify the value fields in value metric. 2/ rename number_of_buckets as num_buckets 3/ use double for the Alert's threshold"
This commit is contained in:
committed by
Android (Google) Code Review
commit
64d467ec09
@@ -34,11 +34,11 @@ namespace statsd {
|
||||
AnomalyTracker::AnomalyTracker(const Alert& alert, const ConfigKey& configKey)
|
||||
: mAlert(alert),
|
||||
mConfigKey(configKey),
|
||||
mNumOfPastBuckets(mAlert.number_of_buckets() - 1) {
|
||||
mNumOfPastBuckets(mAlert.num_buckets() - 1) {
|
||||
VLOG("AnomalyTracker() called");
|
||||
if (mAlert.number_of_buckets() <= 0) {
|
||||
if (mAlert.num_buckets() <= 0) {
|
||||
ALOGE("Cannot create AnomalyTracker with %lld buckets",
|
||||
(long long)mAlert.number_of_buckets());
|
||||
(long long)mAlert.num_buckets());
|
||||
return;
|
||||
}
|
||||
if (!mAlert.has_trigger_if_sum_gt()) {
|
||||
|
||||
@@ -377,7 +377,8 @@ StatsdConfig build_fake_config() {
|
||||
ValueMetric* valueMetric = config.add_value_metric();
|
||||
valueMetric->set_id(11);
|
||||
valueMetric->set_what(109);
|
||||
valueMetric->set_value_field(KERNEL_WAKELOCK_COUNT_KEY);
|
||||
valueMetric->mutable_value_field()->set_field(KERNEL_WAKELOCK_TAG_ID);
|
||||
valueMetric->mutable_value_field()->add_child()->set_field(KERNEL_WAKELOCK_COUNT_KEY);
|
||||
valueMetric->set_condition(201);
|
||||
dimensions = valueMetric->mutable_dimensions();
|
||||
dimensions->set_field(KERNEL_WAKELOCK_TAG_ID);
|
||||
|
||||
@@ -351,6 +351,23 @@ bool IsSubDimension(const DimensionsValue& dimension, const DimensionsValue& sub
|
||||
}
|
||||
}
|
||||
|
||||
long getLongFromDimenValue(const DimensionsValue& dimensionValue) {
|
||||
switch (dimensionValue.value_case()) {
|
||||
case DimensionsValue::ValueCase::kValueInt:
|
||||
return dimensionValue.value_int();
|
||||
case DimensionsValue::ValueCase::kValueLong:
|
||||
return dimensionValue.value_long();
|
||||
case DimensionsValue::ValueCase::kValueBool:
|
||||
return dimensionValue.value_bool() ? 1 : 0;
|
||||
case DimensionsValue::ValueCase::kValueFloat:
|
||||
return (int64_t)dimensionValue.value_float();
|
||||
case DimensionsValue::ValueCase::kValueTuple:
|
||||
case DimensionsValue::ValueCase::kValueStr:
|
||||
case DimensionsValue::ValueCase::VALUE_NOT_SET:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace statsd
|
||||
} // namespace os
|
||||
} // namespace android
|
||||
|
||||
@@ -56,6 +56,8 @@ void DimensionsValueToString(const DimensionsValue& value, std::string *flattene
|
||||
|
||||
bool IsSubDimension(const DimensionsValue& dimension, const DimensionsValue& sub);
|
||||
|
||||
// Helper function to get long value from the DimensionsValue proto.
|
||||
long getLongFromDimenValue(const DimensionsValue& dimensionValue);
|
||||
} // namespace statsd
|
||||
} // namespace os
|
||||
} // namespace android
|
||||
|
||||
@@ -98,9 +98,9 @@ DurationMetricProducer::~DurationMetricProducer() {
|
||||
|
||||
sp<AnomalyTracker> DurationMetricProducer::addAnomalyTracker(const Alert &alert) {
|
||||
std::lock_guard<std::mutex> lock(mMutex);
|
||||
if (alert.trigger_if_sum_gt() > alert.number_of_buckets() * mBucketSizeNs) {
|
||||
ALOGW("invalid alert: threshold (%lld) > possible recordable value (%d x %lld)",
|
||||
alert.trigger_if_sum_gt(), alert.number_of_buckets(),
|
||||
if (alert.trigger_if_sum_gt() > alert.num_buckets() * mBucketSizeNs) {
|
||||
ALOGW("invalid alert: threshold (%f) > possible recordable value (%d x %lld)",
|
||||
alert.trigger_if_sum_gt(), alert.num_buckets(),
|
||||
(long long)mBucketSizeNs);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
#define DEBUG false // STOPSHIP if true
|
||||
#include "Log.h"
|
||||
|
||||
#include "dimension.h"
|
||||
#include "ValueMetricProducer.h"
|
||||
#include "guardrail/StatsdStats.h"
|
||||
#include "stats_log_util.h"
|
||||
@@ -218,7 +219,8 @@ void ValueMetricProducer::onDataPulled(const std::vector<std::shared_ptr<LogEven
|
||||
// For scheduled pulled data, the effective event time is snap to the nearest
|
||||
// bucket boundary to make bucket finalize.
|
||||
uint64_t realEventTime = allData.at(0)->GetTimestampNs();
|
||||
uint64_t eventTime = mStartTimeNs + ((realEventTime - mStartTimeNs)/mBucketSizeNs) * mBucketSizeNs;
|
||||
uint64_t eventTime = mStartTimeNs +
|
||||
((realEventTime - mStartTimeNs)/mBucketSizeNs) * mBucketSizeNs;
|
||||
|
||||
mCondition = false;
|
||||
for (const auto& data : allData) {
|
||||
@@ -272,7 +274,11 @@ void ValueMetricProducer::onMatchedLogEventInternalLocked(
|
||||
}
|
||||
Interval& interval = mCurrentSlicedBucket[eventKey];
|
||||
|
||||
long value = get_value(event);
|
||||
std::shared_ptr<FieldValueMap> valueFieldMap = getValueFields(event);
|
||||
if (valueFieldMap->empty() || valueFieldMap->size() > 1) {
|
||||
return;
|
||||
}
|
||||
const long value = getLongFromDimenValue(valueFieldMap->begin()->second);
|
||||
|
||||
if (mPullTagId != -1) { // for pulled events
|
||||
if (mCondition == true) {
|
||||
@@ -296,15 +302,11 @@ void ValueMetricProducer::onMatchedLogEventInternalLocked(
|
||||
}
|
||||
}
|
||||
|
||||
long ValueMetricProducer::get_value(const LogEvent& event) {
|
||||
status_t err = NO_ERROR;
|
||||
long val = event.GetLong(mValueField, &err);
|
||||
if (err == NO_ERROR) {
|
||||
return val;
|
||||
} else {
|
||||
VLOG("Can't find value in message. %s", event.ToString().c_str());
|
||||
return 0;
|
||||
}
|
||||
std::shared_ptr<FieldValueMap> ValueMetricProducer::getValueFields(const LogEvent& event) {
|
||||
std::shared_ptr<FieldValueMap> valueFields =
|
||||
std::make_shared<FieldValueMap>(event.getFieldValueMap());
|
||||
filterFields(mValueField, valueFields.get());
|
||||
return valueFields;
|
||||
}
|
||||
|
||||
void ValueMetricProducer::flushIfNeededLocked(const uint64_t& eventTimeNs) {
|
||||
|
||||
@@ -70,7 +70,7 @@ private:
|
||||
// Util function to flush the old packet.
|
||||
void flushIfNeededLocked(const uint64_t& eventTime);
|
||||
|
||||
const int32_t mValueField;
|
||||
const FieldMatcher mValueField;
|
||||
|
||||
std::shared_ptr<StatsPullerManager> mStatsPullerManager;
|
||||
|
||||
@@ -103,7 +103,7 @@ private:
|
||||
// TODO: Add a lock to mPastBuckets.
|
||||
std::unordered_map<HashableDimensionKey, std::vector<ValueBucket>> mPastBuckets;
|
||||
|
||||
long get_value(const LogEvent& event);
|
||||
std::shared_ptr<FieldValueMap> getValueFields(const LogEvent& event);
|
||||
|
||||
// Util function to check whether the specified dimension hits the guardrail.
|
||||
bool hitGuardRailLocked(const HashableDimensionKey& newKey);
|
||||
|
||||
@@ -486,9 +486,9 @@ bool initAlerts(const StatsdConfig& config,
|
||||
(long long)alert.metric_id());
|
||||
return false;
|
||||
}
|
||||
if (alert.trigger_if_sum_gt() < 0 || alert.number_of_buckets() <= 0) {
|
||||
ALOGW("invalid alert: threshold=%lld num_buckets= %d",
|
||||
alert.trigger_if_sum_gt(), alert.number_of_buckets());
|
||||
if (alert.trigger_if_sum_gt() < 0 || alert.num_buckets() <= 0) {
|
||||
ALOGW("invalid alert: threshold=%f num_buckets= %d",
|
||||
alert.trigger_if_sum_gt(), alert.num_buckets());
|
||||
return false;
|
||||
}
|
||||
const int metricIndex = itr->second;
|
||||
|
||||
@@ -213,7 +213,7 @@ message ValueMetric {
|
||||
|
||||
optional int64 what = 2;
|
||||
|
||||
optional int32 value_field = 3;
|
||||
optional FieldMatcher value_field = 3;
|
||||
|
||||
optional int64 condition = 4;
|
||||
|
||||
@@ -232,11 +232,11 @@ message Alert {
|
||||
|
||||
optional int64 metric_id = 2;
|
||||
|
||||
optional int32 number_of_buckets = 3;
|
||||
optional int32 num_buckets = 3;
|
||||
|
||||
optional int32 refractory_period_secs = 4;
|
||||
|
||||
optional int64 trigger_if_sum_gt = 5;
|
||||
optional double trigger_if_sum_gt = 5;
|
||||
}
|
||||
|
||||
message AllowedLogSource {
|
||||
|
||||
@@ -89,7 +89,7 @@ StatsdConfig buildGoodConfig() {
|
||||
auto alert = config.add_alert();
|
||||
alert->set_id(3);
|
||||
alert->set_metric_id(3);
|
||||
alert->set_number_of_buckets(10);
|
||||
alert->set_num_buckets(10);
|
||||
alert->set_refractory_period_secs(100);
|
||||
alert->set_trigger_if_sum_gt(100);
|
||||
return config;
|
||||
@@ -138,7 +138,7 @@ StatsdConfig buildAlertWithUnknownMetric() {
|
||||
auto alert = config.add_alert();
|
||||
alert->set_id(3);
|
||||
alert->set_metric_id(2);
|
||||
alert->set_number_of_buckets(10);
|
||||
alert->set_num_buckets(10);
|
||||
alert->set_refractory_period_secs(100);
|
||||
alert->set_trigger_if_sum_gt(100);
|
||||
return config;
|
||||
@@ -222,7 +222,7 @@ StatsdConfig buildDimensionMetricsWithMultiTags() {
|
||||
auto alert = config.add_alert();
|
||||
alert->set_id(103);
|
||||
alert->set_metric_id(3);
|
||||
alert->set_number_of_buckets(10);
|
||||
alert->set_num_buckets(10);
|
||||
alert->set_refractory_period_secs(100);
|
||||
alert->set_trigger_if_sum_gt(100);
|
||||
return config;
|
||||
|
||||
@@ -57,7 +57,7 @@ std::shared_ptr<DimToValMap> MockBucket(
|
||||
TEST(AnomalyTrackerTest, TestConsecutiveBuckets) {
|
||||
const int64_t bucketSizeNs = 30 * NS_PER_SEC;
|
||||
Alert alert;
|
||||
alert.set_number_of_buckets(3);
|
||||
alert.set_num_buckets(3);
|
||||
alert.set_refractory_period_secs(2 * bucketSizeNs / NS_PER_SEC);
|
||||
alert.set_trigger_if_sum_gt(2);
|
||||
|
||||
@@ -177,7 +177,7 @@ TEST(AnomalyTrackerTest, TestConsecutiveBuckets) {
|
||||
TEST(AnomalyTrackerTest, TestSparseBuckets) {
|
||||
const int64_t bucketSizeNs = 30 * NS_PER_SEC;
|
||||
Alert alert;
|
||||
alert.set_number_of_buckets(3);
|
||||
alert.set_num_buckets(3);
|
||||
alert.set_refractory_period_secs(2 * bucketSizeNs / NS_PER_SEC);
|
||||
alert.set_trigger_if_sum_gt(2);
|
||||
|
||||
|
||||
@@ -195,7 +195,7 @@ TEST(CountMetricProducerTest, TestAnomalyDetection) {
|
||||
alert.set_id(11);
|
||||
alert.set_metric_id(1);
|
||||
alert.set_trigger_if_sum_gt(2);
|
||||
alert.set_number_of_buckets(2);
|
||||
alert.set_num_buckets(2);
|
||||
alert.set_refractory_period_secs(1);
|
||||
|
||||
int64_t bucketStartTimeNs = 10000000000;
|
||||
|
||||
@@ -199,7 +199,7 @@ TEST(GaugeMetricProducerTest, TestAnomalyDetection) {
|
||||
alert.set_id(101);
|
||||
alert.set_metric_id(metricId);
|
||||
alert.set_trigger_if_sum_gt(25);
|
||||
alert.set_number_of_buckets(2);
|
||||
alert.set_num_buckets(2);
|
||||
sp<AnomalyTracker> anomalyTracker = gaugeProducer.addAnomalyTracker(alert);
|
||||
|
||||
int tagId = 1;
|
||||
|
||||
@@ -217,7 +217,7 @@ TEST(MaxDurationTrackerTest, TestAnomalyDetection) {
|
||||
alert.set_id(101);
|
||||
alert.set_metric_id(metricId);
|
||||
alert.set_trigger_if_sum_gt(32 * NS_PER_SEC);
|
||||
alert.set_number_of_buckets(2);
|
||||
alert.set_num_buckets(2);
|
||||
alert.set_refractory_period_secs(1);
|
||||
|
||||
unordered_map<HashableDimensionKey, vector<DurationBucket>> buckets;
|
||||
|
||||
@@ -265,7 +265,7 @@ TEST(OringDurationTrackerTest, TestPredictAnomalyTimestamp) {
|
||||
alert.set_id(101);
|
||||
alert.set_metric_id(1);
|
||||
alert.set_trigger_if_sum_gt(40 * NS_PER_SEC);
|
||||
alert.set_number_of_buckets(2);
|
||||
alert.set_num_buckets(2);
|
||||
alert.set_refractory_period_secs(1);
|
||||
|
||||
unordered_map<HashableDimensionKey, vector<DurationBucket>> buckets;
|
||||
@@ -327,7 +327,7 @@ TEST(OringDurationTrackerTest, TestAnomalyDetection) {
|
||||
alert.set_id(101);
|
||||
alert.set_metric_id(1);
|
||||
alert.set_trigger_if_sum_gt(40 * NS_PER_SEC);
|
||||
alert.set_number_of_buckets(2);
|
||||
alert.set_num_buckets(2);
|
||||
alert.set_refractory_period_secs(1);
|
||||
|
||||
unordered_map<HashableDimensionKey, vector<DurationBucket>> buckets;
|
||||
|
||||
@@ -51,7 +51,8 @@ TEST(ValueMetricProducerTest, TestNonDimensionalEvents) {
|
||||
ValueMetric metric;
|
||||
metric.set_id(metricId);
|
||||
metric.mutable_bucket()->set_bucket_size_millis(bucketSizeNs / 1000000);
|
||||
metric.set_value_field(2);
|
||||
metric.mutable_value_field()->set_field(tagId);
|
||||
metric.mutable_value_field()->add_child()->set_field(2);
|
||||
|
||||
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
|
||||
// TODO: pending refactor of StatsPullerManager
|
||||
@@ -127,7 +128,8 @@ TEST(ValueMetricProducerTest, TestEventsWithNonSlicedCondition) {
|
||||
ValueMetric metric;
|
||||
metric.set_id(metricId);
|
||||
metric.mutable_bucket()->set_bucket_size_millis(bucketSizeNs / 1000000);
|
||||
metric.set_value_field(2);
|
||||
metric.mutable_value_field()->set_field(tagId);
|
||||
metric.mutable_value_field()->add_child()->set_field(2);
|
||||
metric.set_condition(StringToId("SCREEN_ON"));
|
||||
|
||||
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
|
||||
@@ -203,7 +205,8 @@ TEST(ValueMetricProducerTest, TestPushedEventsWithoutCondition) {
|
||||
ValueMetric metric;
|
||||
metric.set_id(metricId);
|
||||
metric.mutable_bucket()->set_bucket_size_millis(bucketSizeNs / 1000000);
|
||||
metric.set_value_field(2);
|
||||
metric.mutable_value_field()->set_field(tagId);
|
||||
metric.mutable_value_field()->add_child()->set_field(2);
|
||||
|
||||
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
|
||||
shared_ptr<MockStatsPullerManager> pullerManager =
|
||||
@@ -244,13 +247,14 @@ TEST(ValueMetricProducerTest, TestAnomalyDetection) {
|
||||
alert.set_id(101);
|
||||
alert.set_metric_id(metricId);
|
||||
alert.set_trigger_if_sum_gt(130);
|
||||
alert.set_number_of_buckets(2);
|
||||
alert.set_num_buckets(2);
|
||||
alert.set_refractory_period_secs(3);
|
||||
|
||||
ValueMetric metric;
|
||||
metric.set_id(metricId);
|
||||
metric.mutable_bucket()->set_bucket_size_millis(bucketSizeNs / 1000000);
|
||||
metric.set_value_field(2);
|
||||
metric.mutable_value_field()->set_field(tagId);
|
||||
metric.mutable_value_field()->add_child()->set_field(2);
|
||||
|
||||
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
|
||||
ValueMetricProducer valueProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
|
||||
|
||||
Reference in New Issue
Block a user