summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cmds/statsd/src/anomaly/AnomalyTracker.cpp6
-rw-r--r--cmds/statsd/src/anomaly/AnomalyTracker.h7
-rw-r--r--cmds/statsd/src/guardrail/StatsdStats.cpp31
-rw-r--r--cmds/statsd/src/guardrail/StatsdStats.h15
-rw-r--r--cmds/statsd/src/metrics/DurationMetricProducer.cpp2
-rw-r--r--cmds/statsd/src/metrics/MetricProducer.h2
-rw-r--r--cmds/statsd/src/stats_log.proto6
-rw-r--r--cmds/statsd/tests/anomaly/AnomalyTracker_test.cpp6
-rw-r--r--cmds/statsd/tests/guardrail/StatsdStats_test.cpp17
-rw-r--r--cmds/statsd/tests/metrics/CountMetricProducer_test.cpp2
-rw-r--r--cmds/statsd/tests/metrics/GaugeMetricProducer_test.cpp4
-rw-r--r--cmds/statsd/tests/metrics/MaxDurationTracker_test.cpp2
-rw-r--r--cmds/statsd/tests/metrics/OringDurationTracker_test.cpp4
13 files changed, 84 insertions, 20 deletions
diff --git a/cmds/statsd/src/anomaly/AnomalyTracker.cpp b/cmds/statsd/src/anomaly/AnomalyTracker.cpp
index 7bacb441ee48..e8b408328181 100644
--- a/cmds/statsd/src/anomaly/AnomalyTracker.cpp
+++ b/cmds/statsd/src/anomaly/AnomalyTracker.cpp
@@ -18,6 +18,7 @@
#include "Log.h"
#include "AnomalyTracker.h"
+#include "guardrail/StatsdStats.h"
#include <android/os/IIncidentManager.h>
#include <android/os/IncidentReportArgs.h>
@@ -31,8 +32,9 @@ namespace statsd {
// TODO: Separate DurationAnomalyTracker as a separate subclass and let each MetricProducer
// decide and let which one it wants.
// TODO: Get rid of bucketNumbers, and return to the original circular array method.
-AnomalyTracker::AnomalyTracker(const Alert& alert)
+AnomalyTracker::AnomalyTracker(const Alert& alert, const ConfigKey& configKey)
: mAlert(alert),
+ mConfigKey(configKey),
mNumOfPastBuckets(mAlert.number_of_buckets() - 1) {
VLOG("AnomalyTracker() called");
if (mAlert.number_of_buckets() <= 0) {
@@ -220,6 +222,8 @@ void AnomalyTracker::declareAnomaly(const uint64_t& timestampNs) {
} else {
ALOGW("An anomaly has occurred! (But informing incidentd not requested.)");
}
+
+ StatsdStats::getInstance().noteAnomalyDeclared(mConfigKey, mAlert.name());
}
void AnomalyTracker::declareAnomalyIfAlarmExpired(const HashableDimensionKey& dimensionKey,
diff --git a/cmds/statsd/src/anomaly/AnomalyTracker.h b/cmds/statsd/src/anomaly/AnomalyTracker.h
index 49e83235f73b..874add2ba798 100644
--- a/cmds/statsd/src/anomaly/AnomalyTracker.h
+++ b/cmds/statsd/src/anomaly/AnomalyTracker.h
@@ -18,6 +18,7 @@
#include <gtest/gtest_prod.h>
#include "AnomalyMonitor.h"
+#include "config/ConfigKey.h"
#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h" // Alert
#include "stats_util.h" // HashableDimensionKey and DimToValMap
@@ -35,7 +36,7 @@ using std::shared_ptr;
// Does NOT allow negative values.
class AnomalyTracker : public virtual RefBase {
public:
- AnomalyTracker(const Alert& alert);
+ AnomalyTracker(const Alert& alert, const ConfigKey& configKey);
virtual ~AnomalyTracker();
@@ -107,9 +108,13 @@ public:
protected:
void flushPastBuckets(const int64_t& currBucketNum);
+
// statsd_config.proto Alert message that defines this tracker.
const Alert mAlert;
+ // A reference to the Alert's config key.
+ const ConfigKey& mConfigKey;
+
// Number of past buckets. One less than the total number of buckets needed
// for the anomaly detection (since the current bucket is not in the past).
int mNumOfPastBuckets;
diff --git a/cmds/statsd/src/guardrail/StatsdStats.cpp b/cmds/statsd/src/guardrail/StatsdStats.cpp
index a48ebc35a3e3..b02b9daa4b2d 100644
--- a/cmds/statsd/src/guardrail/StatsdStats.cpp
+++ b/cmds/statsd/src/guardrail/StatsdStats.cpp
@@ -41,9 +41,6 @@ using std::vector;
const int FIELD_ID_BEGIN_TIME = 1;
const int FIELD_ID_END_TIME = 2;
const int FIELD_ID_CONFIG_STATS = 3;
-const int FIELD_ID_MATCHER_STATS = 4;
-const int FIELD_ID_CONDITION_STATS = 5;
-const int FIELD_ID_METRIC_STATS = 6;
const int FIELD_ID_ATOM_STATS = 7;
const int FIELD_ID_UIDMAP_STATS = 8;
const int FIELD_ID_ANOMALY_ALARM_STATS = 9;
@@ -104,11 +101,12 @@ void StatsdStats::noteConfigRemovedInternalLocked(const ConfigKey& key) {
if (it != mConfigStats.end()) {
int32_t nowTimeSec = time(nullptr);
it->second.set_deletion_time_sec(nowTimeSec);
- // Add condition stats, metrics stats, matcher stats
- addSubStatsToConfig(key, it->second);
+ // Add condition stats, metrics stats, matcher stats, alert stats
+ addSubStatsToConfigLocked(key, it->second);
// Remove them after they are added to the config stats.
mMatcherStats.erase(key);
mMetricsStats.erase(key);
+ mAlertStats.erase(key);
mConditionStats.erase(key);
mIceBox.push_back(it->second);
mConfigStats.erase(it);
@@ -222,6 +220,12 @@ void StatsdStats::noteMatcherMatched(const ConfigKey& key, const string& name) {
matcherStats[name]++;
}
+void StatsdStats::noteAnomalyDeclared(const ConfigKey& key, const string& name) {
+ lock_guard<std::mutex> lock(mLock);
+ auto& alertStats = mAlertStats[key];
+ alertStats[name]++;
+}
+
void StatsdStats::noteRegisteredAnomalyAlarmChanged() {
lock_guard<std::mutex> lock(mLock);
mAnomalyAlarmRegisteredStats++;
@@ -254,6 +258,7 @@ void StatsdStats::resetInternalLocked() {
mConditionStats.clear();
mMetricsStats.clear();
std::fill(mPushedAtomStats.begin(), mPushedAtomStats.end(), 0);
+ mAlertStats.clear();
mAnomalyAlarmRegisteredStats = 0;
mMatcherStats.clear();
for (auto& config : mConfigStats) {
@@ -263,10 +268,11 @@ void StatsdStats::resetInternalLocked() {
config.second.clear_matcher_stats();
config.second.clear_condition_stats();
config.second.clear_metric_stats();
+ config.second.clear_alert_stats();
}
}
-void StatsdStats::addSubStatsToConfig(const ConfigKey& key,
+void StatsdStats::addSubStatsToConfigLocked(const ConfigKey& key,
StatsdStatsReport_ConfigStats& configStats) {
// Add matcher stats
if (mMatcherStats.find(key) != mMatcherStats.end()) {
@@ -298,6 +304,16 @@ void StatsdStats::addSubStatsToConfig(const ConfigKey& key,
VLOG("metrics %s max output tuple size %d", stats.first.c_str(), stats.second);
}
}
+ // Add anomaly detection alert stats
+ if (mAlertStats.find(key) != mAlertStats.end()) {
+ const auto& alertStats = mAlertStats[key];
+ for (const auto& stats : alertStats) {
+ auto output = configStats.add_alert_stats();
+ output->set_name(stats.first);
+ output->set_declared_times(stats.second);
+ VLOG("alert %s declared %d times", stats.first.c_str(), stats.second);
+ }
+ }
}
void StatsdStats::dumpStats(std::vector<uint8_t>* output, bool reset) {
@@ -367,7 +383,7 @@ void StatsdStats::dumpStats(std::vector<uint8_t>* output, bool reset) {
}
}
- addSubStatsToConfig(pair.first, configStats);
+ addSubStatsToConfigLocked(pair.first, configStats);
const int numBytes = configStats.ByteSize();
vector<char> buffer(numBytes);
@@ -379,6 +395,7 @@ void StatsdStats::dumpStats(std::vector<uint8_t>* output, bool reset) {
configStats.clear_matcher_stats();
configStats.clear_condition_stats();
configStats.clear_metric_stats();
+ configStats.clear_alert_stats();
}
VLOG("********Atom stats***********");
diff --git a/cmds/statsd/src/guardrail/StatsdStats.h b/cmds/statsd/src/guardrail/StatsdStats.h
index 95a4e2640b19..394056303722 100644
--- a/cmds/statsd/src/guardrail/StatsdStats.h
+++ b/cmds/statsd/src/guardrail/StatsdStats.h
@@ -112,6 +112,14 @@ public:
void noteMatcherMatched(const ConfigKey& key, const std::string& name);
/**
+ * Report that an anomaly detection alert has been declared.
+ *
+ * [key]: The config key that this alert belongs to.
+ * [name]: The name of the alert.
+ */
+ void noteAnomalyDeclared(const ConfigKey& key, const std::string& name);
+
+ /**
* Report an atom event has been logged.
*/
void noteAtomLogged(int atomId, int32_t timeSec);
@@ -183,6 +191,10 @@ private:
// StatsCompanionService.
int mAnomalyAlarmRegisteredStats = 0;
+ // Stores the number of times an anomaly detection alert has been declared
+ // (per config, per alert name).
+ std::map<const ConfigKey, std::map<const std::string, int>> mAlertStats;
+
// Stores how many times a matcher have been matched.
std::map<const ConfigKey, std::map<const std::string, int>> mMatcherStats;
@@ -190,7 +202,8 @@ private:
void resetInternalLocked();
- void addSubStatsToConfig(const ConfigKey& key, StatsdStatsReport_ConfigStats& configStats);
+ void addSubStatsToConfigLocked(const ConfigKey& key,
+ StatsdStatsReport_ConfigStats& configStats);
void noteDataDropped(const ConfigKey& key, int32_t timeSec);
diff --git a/cmds/statsd/src/metrics/DurationMetricProducer.cpp b/cmds/statsd/src/metrics/DurationMetricProducer.cpp
index fd484c25dbaa..cedea301de27 100644
--- a/cmds/statsd/src/metrics/DurationMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/DurationMetricProducer.cpp
@@ -111,7 +111,7 @@ sp<AnomalyTracker> DurationMetricProducer::createAnomalyTracker(const Alert &ale
return nullptr;
}
// TODO: return a DurationAnomalyTracker (which should sublclass AnomalyTracker)
- return new AnomalyTracker(alert);
+ return new AnomalyTracker(alert, mConfigKey);
}
void DurationMetricProducer::startNewProtoOutputStreamLocked(long long startTime) {
diff --git a/cmds/statsd/src/metrics/MetricProducer.h b/cmds/statsd/src/metrics/MetricProducer.h
index 819df7705a75..71d6d07920f8 100644
--- a/cmds/statsd/src/metrics/MetricProducer.h
+++ b/cmds/statsd/src/metrics/MetricProducer.h
@@ -94,7 +94,7 @@ public:
}
virtual sp<AnomalyTracker> createAnomalyTracker(const Alert &alert) {
- return new AnomalyTracker(alert);
+ return new AnomalyTracker(alert, mConfigKey);
}
void addAnomalyTracker(sp<AnomalyTracker> tracker) {
diff --git a/cmds/statsd/src/stats_log.proto b/cmds/statsd/src/stats_log.proto
index 79c47277b355..f8b91fe0ef0a 100644
--- a/cmds/statsd/src/stats_log.proto
+++ b/cmds/statsd/src/stats_log.proto
@@ -193,6 +193,11 @@ message StatsdStatsReport {
optional int32 max_tuple_counts = 2;
}
+ message AlertStats {
+ optional string name = 1;
+ optional int32 declared_times = 2;
+ }
+
message ConfigStats {
optional int32 uid = 1;
optional string name = 2;
@@ -210,6 +215,7 @@ message StatsdStatsReport {
repeated MatcherStats matcher_stats = 13;
repeated ConditionStats condition_stats = 14;
repeated MetricStats metric_stats = 15;
+ repeated AlertStats alert_stats = 16;
}
repeated ConfigStats config_stats = 3;
diff --git a/cmds/statsd/tests/anomaly/AnomalyTracker_test.cpp b/cmds/statsd/tests/anomaly/AnomalyTracker_test.cpp
index 65c2a05543b9..f38576398f11 100644
--- a/cmds/statsd/tests/anomaly/AnomalyTracker_test.cpp
+++ b/cmds/statsd/tests/anomaly/AnomalyTracker_test.cpp
@@ -30,6 +30,8 @@ namespace android {
namespace os {
namespace statsd {
+const ConfigKey kConfigKey(0, "test");
+
void AddValueToBucket(const std::vector<std::pair<string, long>>& key_value_pair_list,
std::shared_ptr<DimToValMap> bucket) {
for (auto itr = key_value_pair_list.begin(); itr != key_value_pair_list.end(); itr++) {
@@ -51,7 +53,7 @@ TEST(AnomalyTrackerTest, TestConsecutiveBuckets) {
alert.set_refractory_period_secs(2 * bucketSizeNs / NS_PER_SEC);
alert.set_trigger_if_sum_gt(2);
- AnomalyTracker anomalyTracker(alert);
+ AnomalyTracker anomalyTracker(alert, kConfigKey);
std::shared_ptr<DimToValMap> bucket0 = MockBucket({{"a", 1}, {"b", 2}, {"c", 1}});
int64_t eventTimestamp0 = 10;
@@ -168,7 +170,7 @@ TEST(AnomalyTrackerTest, TestSparseBuckets) {
alert.set_refractory_period_secs(2 * bucketSizeNs / NS_PER_SEC);
alert.set_trigger_if_sum_gt(2);
- AnomalyTracker anomalyTracker(alert);
+ AnomalyTracker anomalyTracker(alert, kConfigKey);
std::shared_ptr<DimToValMap> bucket9 = MockBucket({{"a", 1}, {"b", 2}, {"c", 1}});
std::shared_ptr<DimToValMap> bucket16 = MockBucket({{"b", 4}});
diff --git a/cmds/statsd/tests/guardrail/StatsdStats_test.cpp b/cmds/statsd/tests/guardrail/StatsdStats_test.cpp
index 7baa9003056e..9fed4f8b5e30 100644
--- a/cmds/statsd/tests/guardrail/StatsdStats_test.cpp
+++ b/cmds/statsd/tests/guardrail/StatsdStats_test.cpp
@@ -118,6 +118,10 @@ TEST(StatsdStatsTest, TestSubStats) {
stats.noteMetricDimensionSize(key, "metric1", 201);
stats.noteMetricDimensionSize(key, "metric1", 202);
+ stats.noteAnomalyDeclared(key, "alert1");
+ stats.noteAnomalyDeclared(key, "alert1");
+ stats.noteAnomalyDeclared(key, "alert2");
+
// broadcast-> 2
stats.noteBroadcastSent(key);
stats.noteBroadcastSent(key);
@@ -142,7 +146,6 @@ TEST(StatsdStatsTest, TestSubStats) {
EXPECT_EQ(3, configReport.dump_report_time_sec_size());
EXPECT_EQ(2, configReport.matcher_stats_size());
-
// matcher1 is the first in the list
if (!configReport.matcher_stats(0).name().compare("matcher1")) {
EXPECT_EQ(2, configReport.matcher_stats(0).matched_times());
@@ -157,6 +160,13 @@ TEST(StatsdStatsTest, TestSubStats) {
EXPECT_EQ("matcher1", configReport.matcher_stats(1).name());
}
+ EXPECT_EQ(2, configReport.alert_stats_size());
+ bool alert1first = !configReport.alert_stats(0).name().compare("alert1");
+ EXPECT_EQ("alert1", configReport.alert_stats(alert1first ? 0 : 1).name());
+ EXPECT_EQ(2, configReport.alert_stats(alert1first ? 0 : 1).declared_times());
+ EXPECT_EQ("alert2", configReport.alert_stats(alert1first ? 1 : 0).name());
+ EXPECT_EQ(1, configReport.alert_stats(alert1first ? 1 : 0).declared_times());
+
EXPECT_EQ(1, configReport.condition_stats_size());
EXPECT_EQ("condition1", configReport.condition_stats(0).name());
EXPECT_EQ(250, configReport.condition_stats(0).max_tuple_counts());
@@ -169,6 +179,7 @@ TEST(StatsdStatsTest, TestSubStats) {
stats.noteMatcherMatched(key, "matcher99");
stats.noteConditionDimensionSize(key, "condition99", 300);
stats.noteMetricDimensionSize(key, "metric99", 270);
+ stats.noteAnomalyDeclared(key, "alert99");
// now the config stats should only contain the stats about the new event.
stats.dumpStats(&output, false);
@@ -187,6 +198,10 @@ TEST(StatsdStatsTest, TestSubStats) {
EXPECT_EQ(1, configReport2.metric_stats_size());
EXPECT_EQ("metric99", configReport2.metric_stats(0).name());
EXPECT_EQ(270, configReport2.metric_stats(0).max_tuple_counts());
+
+ EXPECT_EQ(1, configReport2.alert_stats_size());
+ EXPECT_EQ("alert99", configReport2.alert_stats(0).name());
+ EXPECT_EQ(1, configReport2.alert_stats(0).declared_times());
}
TEST(StatsdStatsTest, TestAtomLog) {
diff --git a/cmds/statsd/tests/metrics/CountMetricProducer_test.cpp b/cmds/statsd/tests/metrics/CountMetricProducer_test.cpp
index dc42943e8233..4e24ab530155 100644
--- a/cmds/statsd/tests/metrics/CountMetricProducer_test.cpp
+++ b/cmds/statsd/tests/metrics/CountMetricProducer_test.cpp
@@ -196,7 +196,7 @@ TEST(CountMetricProducerTest, TestAnomalyDetection) {
int64_t bucket2StartTimeNs = bucketStartTimeNs + bucketSizeNs;
int64_t bucket3StartTimeNs = bucketStartTimeNs + 2 * bucketSizeNs;
- sp<AnomalyTracker> anomalyTracker = new AnomalyTracker(alert);
+ sp<AnomalyTracker> anomalyTracker = new AnomalyTracker(alert, kConfigKey);
CountMetric metric;
metric.set_name("1");
diff --git a/cmds/statsd/tests/metrics/GaugeMetricProducer_test.cpp b/cmds/statsd/tests/metrics/GaugeMetricProducer_test.cpp
index ed13db25397a..59475d266217 100644
--- a/cmds/statsd/tests/metrics/GaugeMetricProducer_test.cpp
+++ b/cmds/statsd/tests/metrics/GaugeMetricProducer_test.cpp
@@ -33,6 +33,8 @@ namespace android {
namespace os {
namespace statsd {
+const ConfigKey kConfigKey(0, "test");
+
TEST(GaugeMetricProducerTest, TestWithCondition) {
int64_t bucketStartTimeNs = 10000000000;
int64_t bucketSizeNs = 60 * 1000 * 1000 * 1000LL;
@@ -148,7 +150,7 @@ TEST(GaugeMetricProducerTest, TestAnomalyDetection) {
alert.set_metric_name("1");
alert.set_trigger_if_sum_gt(25);
alert.set_number_of_buckets(2);
- sp<AnomalyTracker> anomalyTracker = new AnomalyTracker(alert);
+ sp<AnomalyTracker> anomalyTracker = new AnomalyTracker(alert, kConfigKey);
gaugeProducer.addAnomalyTracker(anomalyTracker);
std::shared_ptr<LogEvent> event1 = std::make_shared<LogEvent>(1, bucketStartTimeNs + 1);
diff --git a/cmds/statsd/tests/metrics/MaxDurationTracker_test.cpp b/cmds/statsd/tests/metrics/MaxDurationTracker_test.cpp
index 1adcc1146c42..4e5e0d6dbfb3 100644
--- a/cmds/statsd/tests/metrics/MaxDurationTracker_test.cpp
+++ b/cmds/statsd/tests/metrics/MaxDurationTracker_test.cpp
@@ -208,7 +208,7 @@ TEST(MaxDurationTrackerTest, TestAnomalyDetection) {
uint64_t eventStartTimeNs = bucketStartTimeNs + NS_PER_SEC + 1;
uint64_t bucketSizeNs = 30 * NS_PER_SEC;
- sp<AnomalyTracker> anomalyTracker = new AnomalyTracker(alert);
+ sp<AnomalyTracker> anomalyTracker = new AnomalyTracker(alert, kConfigKey);
MaxDurationTracker tracker(kConfigKey, "metric", eventKey, wizard, -1, true, bucketStartTimeNs,
bucketSizeNs, {anomalyTracker});
diff --git a/cmds/statsd/tests/metrics/OringDurationTracker_test.cpp b/cmds/statsd/tests/metrics/OringDurationTracker_test.cpp
index fa7b9a734524..99d3e054d893 100644
--- a/cmds/statsd/tests/metrics/OringDurationTracker_test.cpp
+++ b/cmds/statsd/tests/metrics/OringDurationTracker_test.cpp
@@ -269,7 +269,7 @@ TEST(OringDurationTrackerTest, TestPredictAnomalyTimestamp) {
uint64_t eventStartTimeNs = bucketStartTimeNs + NS_PER_SEC + 1;
uint64_t bucketSizeNs = 30 * NS_PER_SEC;
- sp<AnomalyTracker> anomalyTracker = new AnomalyTracker(alert);
+ sp<AnomalyTracker> anomalyTracker = new AnomalyTracker(alert, kConfigKey);
OringDurationTracker tracker(kConfigKey, "metric", eventKey, wizard, 1, true, bucketStartTimeNs,
bucketSizeNs, {anomalyTracker});
@@ -331,7 +331,7 @@ TEST(OringDurationTrackerTest, TestAnomalyDetection) {
uint64_t eventStartTimeNs = bucketStartTimeNs + NS_PER_SEC + 1;
uint64_t bucketSizeNs = 30 * NS_PER_SEC;
- sp<AnomalyTracker> anomalyTracker = new AnomalyTracker(alert);
+ sp<AnomalyTracker> anomalyTracker = new AnomalyTracker(alert, kConfigKey);
OringDurationTracker tracker(kConfigKey, "metric", eventKey, wizard, 1, true /*nesting*/,
bucketStartTimeNs, bucketSizeNs, {anomalyTracker});