Add StatsdStats and guardrail.
+ StatsdStats is the global class that tracks the stats about statsd.
+ Added guardrail for classes that have a map which could potentially grow
unboundedly with the number of logs.
TODO: add unit tests & CTS for StatsdStats, and guardrail
add stats for pulled atoms.
Test: statsd_test
Change-Id: I0ea562de4dd3f6162f7923a9c193420b482c1d51
diff --git a/cmds/statsd/src/metrics/ValueMetricProducer.cpp b/cmds/statsd/src/metrics/ValueMetricProducer.cpp
index cc02c69..66c8419 100644
--- a/cmds/statsd/src/metrics/ValueMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/ValueMetricProducer.cpp
@@ -18,6 +18,7 @@
#include "Log.h"
#include "ValueMetricProducer.h"
+#include "guardrail/StatsdStats.h"
#include <cutils/log.h>
#include <limits.h>
@@ -67,11 +68,12 @@
static const uint64_t kDefaultBucketSizeMillis = 60 * 60 * 1000L;
// ValueMetric has a minimum bucket size of 10min so that we don't pull too frequently
-ValueMetricProducer::ValueMetricProducer(const ValueMetric& metric, const int conditionIndex,
+ValueMetricProducer::ValueMetricProducer(const ConfigKey& key, const ValueMetric& metric,
+ const int conditionIndex,
const sp<ConditionWizard>& wizard, const int pullTagId,
const uint64_t startTimeNs,
shared_ptr<StatsPullerManager> statsPullerManager)
- : MetricProducer(startTimeNs, conditionIndex, wizard),
+ : MetricProducer(key, startTimeNs, conditionIndex, wizard),
mMetric(metric),
mStatsPullerManager(statsPullerManager),
mPullTagId(pullTagId) {
@@ -103,10 +105,11 @@
}
// for testing
-ValueMetricProducer::ValueMetricProducer(const ValueMetric& metric, const int conditionIndex,
+ValueMetricProducer::ValueMetricProducer(const ConfigKey& key, const ValueMetric& metric,
+ const int conditionIndex,
const sp<ConditionWizard>& wizard, const int pullTagId,
const uint64_t startTimeNs)
- : ValueMetricProducer(metric, conditionIndex, wizard, pullTagId, startTimeNs,
+ : ValueMetricProducer(key, metric, conditionIndex, wizard, pullTagId, startTimeNs,
make_shared<StatsPullerManager>()) {
}
@@ -238,6 +241,27 @@
}
}
+bool ValueMetricProducer::hitGuardRail(const HashableDimensionKey& newKey) {
+ // ===========GuardRail==============
+ // 1. Report the tuple count if the tuple count > soft limit
+ if (mCurrentSlicedBucket.find(newKey) != mCurrentSlicedBucket.end()) {
+ return false;
+ }
+ if (mCurrentSlicedBucket.size() > StatsdStats::kDimensionKeySizeSoftLimit - 1) {
+ size_t newTupleCount = mCurrentSlicedBucket.size() + 1;
+ StatsdStats::getInstance().noteMetricDimensionSize(mConfigKey, mMetric.name(),
+ newTupleCount);
+ // 2. Don't add more tuples, we are above the allowed threshold. Drop the data.
+ if (newTupleCount > StatsdStats::kDimensionKeySizeHardLimit) {
+ ALOGE("ValueMetric %s dropping data for dimension key %s", mMetric.name().c_str(),
+ newKey.c_str());
+ return true;
+ }
+ }
+
+ return false;
+}
+
void ValueMetricProducer::onMatchedLogEventInternal(
const size_t matcherIndex, const HashableDimensionKey& eventKey,
const map<string, HashableDimensionKey>& conditionKey, bool condition,
@@ -249,6 +273,9 @@
return;
}
+ if (hitGuardRail(eventKey)) {
+ return;
+ }
Interval& interval = mCurrentSlicedBucket[eventKey];
long value = get_value(event);