const int FIELD_ID_CONFIG_STATS_METRIC_STATS = 15;
const int FIELD_ID_CONFIG_STATS_ALERT_STATS = 16;
const int FIELD_ID_CONFIG_STATS_METRIC_DIMENSION_IN_CONDITION_STATS = 17;
+const int FIELD_ID_CONFIG_STATS_ANNOTATION = 18;
+const int FIELD_ID_CONFIG_STATS_ANNOTATION_INT64 = 1;
+const int FIELD_ID_CONFIG_STATS_ANNOTATION_INT32 = 2;
const int FIELD_ID_MATCHER_STATS_ID = 1;
const int FIELD_ID_MATCHER_STATS_COUNT = 2;
mIceBox.push_back(stats);
}
-void StatsdStats::noteConfigReceived(const ConfigKey& key, int metricsCount, int conditionsCount,
- int matchersCount, int alertsCount, bool isValid) {
+void StatsdStats::noteConfigReceived(
+ const ConfigKey& key, int metricsCount, int conditionsCount, int matchersCount,
+ int alertsCount, const std::list<std::pair<const int64_t, const int32_t>>& annotations,
+ bool isValid) {
lock_guard<std::mutex> lock(mLock);
int32_t nowTimeSec = getWallClockSec();
configStats->matcher_count = matchersCount;
configStats->alert_count = alertsCount;
configStats->is_valid = isValid;
+ for (auto& v : annotations) {
+ configStats->annotations.emplace_back(v);
+ }
if (isValid) {
mConfigStats[key] = configStats;
config.second->broadcast_sent_time_sec.clear();
config.second->data_drop_time_sec.clear();
config.second->dump_report_time_sec.clear();
+ config.second->annotations.clear();
config.second->matcher_stats.clear();
config.second->condition_stats.clear();
config.second->metric_stats.clear();
configStats->deletion_time_sec, configStats->metric_count,
configStats->condition_count, configStats->matcher_count, configStats->alert_count,
configStats->is_valid);
+ for (const auto& annotation : configStats->annotations) {
+ fprintf(out, "\tannotation: %lld, %d\n", (long long)annotation.first,
+ annotation.second);
+ }
+
for (const auto& broadcastTime : configStats->broadcast_sent_time_sec) {
fprintf(out, "\tbroadcast time: %d\n", broadcastTime);
}
dump);
}
+ for (const auto& annotation : configStats.annotations) {
+ uint64_t token = proto->start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED |
+ FIELD_ID_CONFIG_STATS_ANNOTATION);
+ proto->write(FIELD_TYPE_INT64 | FIELD_ID_CONFIG_STATS_ANNOTATION_INT64,
+ (long long)annotation.first);
+ proto->write(FIELD_TYPE_INT32 | FIELD_ID_CONFIG_STATS_ANNOTATION_INT32, annotation.second);
+ proto->end(token);
+ }
+
for (const auto& pair : configStats.matcher_stats) {
uint64_t tmpToken = proto->start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED |
FIELD_ID_CONFIG_STATS_MATCHER_STATS);
// Stores the number of times an anomaly detection alert has been declared.
// The map size is capped by kMaxConfigCount.
std::map<const int64_t, int> alert_stats;
+
+ // Stores the config ID for each sub-config used.
+ std::list<std::pair<const int64_t, const int32_t>> annotations;
};
struct UidMapStats {
* If the config is not valid, this config stats will be put into icebox immediately.
*/
void noteConfigReceived(const ConfigKey& key, int metricsCount, int conditionsCount,
- int matchersCount, int alertCount, bool isValid);
+ int matchersCount, int alertCount,
+ const std::list<std::pair<const int64_t, const int32_t>>& annotations,
+ bool isValid);
/**
* Report a config has been removed.
*/
#include <utils/SystemClock.h>
using android::util::FIELD_COUNT_REPEATED;
+using android::util::FIELD_TYPE_INT32;
+using android::util::FIELD_TYPE_INT64;
using android::util::FIELD_TYPE_MESSAGE;
using android::util::ProtoOutputStream;
namespace statsd {
const int FIELD_ID_METRICS = 1;
+const int FIELD_ID_ANNOTATIONS = 7;
+const int FIELD_ID_ANNOTATIONS_INT64 = 1;
+const int FIELD_ID_ANNOTATIONS_INT32 = 2;
MetricsManager::MetricsManager(const ConfigKey& key, const StatsdConfig& config,
const long timeBaseSec, const long currentTimeSec,
}
}
+ // Store the sub-configs used.
+ for (const auto& annotation : config.annotation()) {
+ mAnnotations.emplace_back(annotation.field_int64(), annotation.field_int32());
+ }
+
// Guardrail. Reject the config if it's too big.
if (mAllMetricProducers.size() > StatsdStats::kMaxMetricCountPerConfig ||
mAllConditionTrackers.size() > StatsdStats::kMaxConditionCountPerConfig ||
mConfigValid = false;
}
// no matter whether this config is valid, log it in the stats.
- StatsdStats::getInstance().noteConfigReceived(key, mAllMetricProducers.size(),
- mAllConditionTrackers.size(),
- mAllAtomMatchers.size(),
- mAllAnomalyTrackers.size(),
- mConfigValid);
+ StatsdStats::getInstance().noteConfigReceived(
+ key, mAllMetricProducers.size(), mAllConditionTrackers.size(), mAllAtomMatchers.size(),
+ mAllAnomalyTrackers.size(), mAnnotations, mConfigValid);
}
MetricsManager::~MetricsManager() {
protoOutput->end(token);
}
}
+ for (const auto& annotation : mAnnotations) {
+ uint64_t token = protoOutput->start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED |
+ FIELD_ID_ANNOTATIONS);
+ protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_ANNOTATIONS_INT64,
+ (long long)annotation.first);
+ protoOutput->write(FIELD_TYPE_INT32 | FIELD_ID_ANNOTATIONS_INT32, annotation.second);
+ protoOutput->end(token);
+ }
mLastReportTimeNs = dumpTimeStampNs;
mLastReportWallClockNs = getWallClockNs();
VLOG("=========================Metric Reports End==========================");
// Logs from uids that are not in the list will be ignored to avoid spamming.
std::set<int32_t> mAllowedLogSources;
+ // Contains the annotations passed in with StatsdConfig.
+ std::list<std::pair<const int64_t, const int32_t>> mAnnotations;
+
// To guard access to mAllowedLogSources
mutable std::mutex mAllowedLogSourcesMutex;
optional int64 last_report_wall_clock_nanos = 5;
optional int64 current_report_wall_clock_nanos = 6;
+
+ message Annotation {
+ optional int64 field_int64 = 1;
+ optional int32 field_int32 = 2;
+ }
+ repeated Annotation annotation = 7;
}
message ConfigMetricsReportList {
repeated MetricStats metric_stats = 15;
repeated AlertStats alert_stats = 16;
repeated MetricStats metric_dimension_in_condition_stats = 17;
+ message Annotation {
+ optional int64 field_int64 = 1;
+ optional int32 field_int32 = 2;
+ }
+ repeated Annotation annotation = 18;
}
repeated ConfigStats config_stats = 3;
repeated string allowed_log_source = 12;
repeated int64 no_report_metric = 13;
+
+ message Annotation {
+ optional int64 field_int64 = 1;
+ optional int32 field_int32 = 2;
+ }
+ repeated Annotation annotation = 14;
+
+ // Field number 1000 is reserved for later use.
+ reserved 1000;
}
EXPECT_EQ(2, uidmap.snapshots(0).package_info_size());
}
+TEST(StatsLogProcessorTest, TestReportIncludesSubConfig) {
+ // Setup simple config key corresponding to empty config.
+ sp<UidMap> m = new UidMap();
+ sp<AlarmMonitor> anomalyAlarmMonitor;
+ sp<AlarmMonitor> subscriberAlarmMonitor;
+ int broadcastCount = 0;
+ StatsLogProcessor p(m, anomalyAlarmMonitor, subscriberAlarmMonitor, 0,
+ [&broadcastCount](const ConfigKey& key) { broadcastCount++; });
+ ConfigKey key(3, 4);
+ StatsdConfig config;
+ auto annotation = config.add_annotation();
+ annotation->set_field_int64(1);
+ annotation->set_field_int32(2);
+ config.add_allowed_log_source("AID_ROOT");
+ p.OnConfigUpdated(1, key, config);
+
+ // Expect to get no metrics, but snapshot specified above in uidmap.
+ vector<uint8_t> bytes;
+ p.onDumpReport(key, 1, &bytes);
+
+ ConfigMetricsReportList output;
+ output.ParseFromArray(bytes.data(), bytes.size());
+ EXPECT_TRUE(output.reports_size() > 0);
+ auto report = output.reports(0);
+ EXPECT_EQ(1, report.annotation_size());
+ EXPECT_EQ(1, report.annotation(0).field_int64());
+ EXPECT_EQ(2, report.annotation(0).field_int32());
+}
+
#else
GTEST_LOG_(INFO) << "This test does nothing.\n";
#endif
const int conditionsCount = 20;
const int matchersCount = 30;
const int alertsCount = 10;
- stats.noteConfigReceived(key, metricsCount, conditionsCount, matchersCount, alertsCount,
+ stats.noteConfigReceived(key, metricsCount, conditionsCount, matchersCount, alertsCount, {},
true /*valid config*/);
vector<uint8_t> output;
stats.dumpStats(&output, false /*reset stats*/);
const int conditionsCount = 20;
const int matchersCount = 30;
const int alertsCount = 10;
- stats.noteConfigReceived(key, metricsCount, conditionsCount, matchersCount, alertsCount,
+ stats.noteConfigReceived(key, metricsCount, conditionsCount, matchersCount, alertsCount, {},
false /*bad config*/);
vector<uint8_t> output;
stats.dumpStats(&output, false);
const int conditionsCount = 20;
const int matchersCount = 30;
const int alertsCount = 10;
- stats.noteConfigReceived(key, metricsCount, conditionsCount, matchersCount, alertsCount, true);
+ stats.noteConfigReceived(key, metricsCount, conditionsCount, matchersCount, alertsCount, {},
+ true);
vector<uint8_t> output;
stats.dumpStats(&output, false);
StatsdStatsReport report;
TEST(StatsdStatsTest, TestSubStats) {
StatsdStats stats;
ConfigKey key(0, 12345);
- stats.noteConfigReceived(key, 2, 3, 4, 5, true);
+ stats.noteConfigReceived(key, 2, 3, 4, 5, {std::make_pair(123, 456)}, true);
stats.noteMatcherMatched(key, StringToId("matcher1"));
stats.noteMatcherMatched(key, StringToId("matcher1"));
EXPECT_EQ(2, configReport.broadcast_sent_time_sec_size());
EXPECT_EQ(1, configReport.data_drop_time_sec_size());
EXPECT_EQ(3, configReport.dump_report_time_sec_size());
+ EXPECT_EQ(1, configReport.annotation_size());
+ EXPECT_EQ(123, configReport.annotation(0).field_int64());
+ EXPECT_EQ(456, configReport.annotation(0).field_int32());
EXPECT_EQ(2, configReport.matcher_stats_size());
// matcher1 is the first in the list
timestamps.push_back(i);
}
ConfigKey key(0, 12345);
- stats.noteConfigReceived(key, 2, 3, 4, 5, true);
+ stats.noteConfigReceived(key, 2, 3, 4, 5, {}, true);
for (int i = 0; i < StatsdStats::kMaxTimestampCount; i++) {
stats.noteDataDropped(key, timestamps[i]);