//
// Copyright (C) 2012 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.
//
#include "shill/scope_logger.h"
#include <vector>
#include <base/strings/string_tokenizer.h>
#include <base/strings/string_util.h>
using base::StringTokenizer;
using std::string;
using std::vector;
namespace shill {
namespace {
const int kDefaultVerboseLevel = 0;
// Scope names corresponding to the scope defined by ScopeLogger::Scope.
const char* const kScopeNames[] = {
"binder",
"cellular",
"connection",
"crypto",
"daemon",
"dbus",
"device",
"dhcp",
"dns",
"ethernet",
"http",
"httpproxy",
"inet",
"link",
"manager",
"metrics",
"modem",
"portal",
"power",
"ppp",
"pppoe",
"profile",
"property",
"resolver",
"route",
"rtnl",
"service",
"storage",
"task",
"vpn",
"wifi",
"wimax",
};
static_assert(arraysize(kScopeNames) == ScopeLogger::kNumScopes,
"Scope tags do not have expected number of strings");
// ScopeLogger needs to be a 'leaky' singleton as it needs to survive to
// handle logging till the very end of the shill process. Making ScopeLogger
// leaky is fine as it does not need to clean up or release any resource at
// destruction.
base::LazyInstance<ScopeLogger>::Leaky g_scope_logger =
LAZY_INSTANCE_INITIALIZER;
} // namespace
// static
ScopeLogger* ScopeLogger::GetInstance() {
return g_scope_logger.Pointer();
}
ScopeLogger::ScopeLogger()
: verbose_level_(kDefaultVerboseLevel) {
}
ScopeLogger::~ScopeLogger() {
}
bool ScopeLogger::IsLogEnabled(Scope scope, int verbose_level) const {
return IsScopeEnabled(scope) && verbose_level <= verbose_level_;
}
bool ScopeLogger::IsScopeEnabled(Scope scope) const {
CHECK_GE(scope, 0);
CHECK_LT(scope, kNumScopes);
return scope_enabled_[scope];
}
string ScopeLogger::GetAllScopeNames() const {
vector<string> names(kScopeNames, kScopeNames + arraysize(kScopeNames));
return base::JoinString(names, "+");
}
string ScopeLogger::GetEnabledScopeNames() const {
vector<string> names;
for (size_t i = 0; i < arraysize(kScopeNames); ++i) {
if (scope_enabled_[i])
names.push_back(kScopeNames[i]);
}
return base::JoinString(names, "+");
}
void ScopeLogger::EnableScopesByName(const string& expression) {
if (expression.empty()) {
DisableAllScopes();
return;
}
// As described in the header file, if the first scope name in the
// sequence specified by |expression| is not prefixed by a plus or
// minus sign, it indicates that all scopes are first disabled before
// enabled by |expression|.
if (expression[0] != '+' && expression[0] != '-')
DisableAllScopes();
bool enable_scope = true;
StringTokenizer tokenizer(expression, "+-");
tokenizer.set_options(StringTokenizer::RETURN_DELIMS);
while (tokenizer.GetNext()) {
if (tokenizer.token_is_delim()) {
enable_scope = (tokenizer.token() == "+");
continue;
}
if (tokenizer.token().empty())
continue;
size_t i;
for (i = 0; i < arraysize(kScopeNames); ++i) {
if (tokenizer.token() == kScopeNames[i]) {
SetScopeEnabled(static_cast<Scope>(i), enable_scope);
break;
}
}
LOG_IF(WARNING, i == arraysize(kScopeNames))
<< "Unknown scope '" << tokenizer.token() << "'";
}
}
void ScopeLogger::RegisterScopeEnableChangedCallback(
Scope scope, ScopeEnableChangedCallback callback) {
CHECK_GE(scope, 0);
CHECK_LT(scope, kNumScopes);
log_scope_callbacks_[scope].push_back(callback);
}
void ScopeLogger::DisableAllScopes() {
// Iterate over all scopes so the notification side-effect occurs.
for (size_t i = 0; i < arraysize(kScopeNames); ++i) {
SetScopeEnabled(static_cast<Scope>(i), false);
}
}
void ScopeLogger::SetScopeEnabled(Scope scope, bool enabled) {
CHECK_GE(scope, 0);
CHECK_LT(scope, kNumScopes);
if (scope_enabled_[scope] != enabled) {
for (const auto& callback : log_scope_callbacks_[scope]) {
callback.Run(enabled);
}
}
scope_enabled_[scope] = enabled;
}
} // namespace shill