blob: cb7420683380b36579d98911f2095f4d22f5d58d [file] [log] [blame]
/*
* Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#define LOG_TAG "MetricManager"
#define DEBUG true // STOPSHIP if true
#define VLOG(...) \
if (DEBUG) ALOGD(__VA_ARGS__);
#include "MetricsManager.h"
#include <cutils/log.h>
#include <log/logprint.h>
#include "CountMetricProducer.h"
#include "parse_util.h"
using std::make_unique;
using std::set;
using std::string;
using std::unique_ptr;
using std::unordered_map;
using std::vector;
namespace android {
namespace os {
namespace statsd {
MetricsManager::MetricsManager(const StatsdConfig& config) : mConfig(config), mLogMatchers() {
std::unordered_map<string, LogEntryMatcher> matcherMap;
std::unordered_map<string, sp<ConditionTracker>> conditionMap;
for (int i = 0; i < config.log_entry_matcher_size(); i++) {
const LogEntryMatcher& logMatcher = config.log_entry_matcher(i);
mMatchers.push_back(logMatcher);
matcherMap[config.log_entry_matcher(i).name()] = logMatcher;
mLogMatchers[logMatcher.name()] = vector<unique_ptr<MetricProducer>>();
// Collect all the tag ids that are interesting
set<int> tagIds = LogEntryMatcherManager::getTagIdsFromMatcher(logMatcher);
mTagIds.insert(tagIds.begin(), tagIds.end());
}
for (int i = 0; i < config.condition_size(); i++) {
const Condition& condition = config.condition(i);
conditionMap[condition.name()] = new ConditionTracker(condition);
}
// Build MetricProducers for each metric defined in config.
// (1) build CountMetricProducer
for (int i = 0; i < config.count_metric_size(); i++) {
const CountMetric& metric = config.count_metric(i);
auto it = mLogMatchers.find(metric.what());
if (it == mLogMatchers.end()) {
ALOGW("cannot find the LogEntryMatcher %s in config", metric.what().c_str());
continue;
}
if (metric.has_condition()) {
auto condition_it = conditionMap.find(metric.condition());
if (condition_it == conditionMap.end()) {
ALOGW("cannot find the Condition %s in the config", metric.condition().c_str());
continue;
}
it->second.push_back(make_unique<CountMetricProducer>(metric, condition_it->second));
} else {
it->second.push_back(make_unique<CountMetricProducer>(metric));
}
}
// TODO: build other types of metrics too.
}
MetricsManager::~MetricsManager() {
VLOG("~MetricManager()");
}
void MetricsManager::finish() {
for (auto const& entryPair : mLogMatchers) {
for (auto const& metric : entryPair.second) {
metric->finish();
}
}
}
// Consume the stats log if it's interesting to this metric.
void MetricsManager::onLogEvent(const log_msg& logMsg) {
int tagId = getTagId(logMsg);
if (mTagIds.find(tagId) == mTagIds.end()) {
// not interesting...
return;
}
// Since at least one of the metrics is interested in this event, we parse it now.
LogEventWrapper event = LogEntryMatcherManager::parseLogEvent(logMsg);
// Evaluate the conditions. Order matters, this should happen
// before sending the event to metrics
for (auto& condition : mConditionTracker) {
condition->evaluateCondition(event);
}
// Now find out which LogMatcher matches this event, and let relevant metrics know.
for (auto matcher : mMatchers) {
if (LogEntryMatcherManager::matches(matcher, event)) {
auto it = mLogMatchers.find(matcher.name());
if (it != mLogMatchers.end()) {
for (auto const& it2 : it->second) {
// Only metrics that matches this event get notified.
it2->onMatchedLogEvent(event);
}
} else {
// TODO: we should remove any redundant matchers that the config provides.
ALOGW("Matcher not used by any metrics.");
}
}
}
}
} // namespace statsd
} // namespace os
} // namespace android