1// 2// Copyright (C) 2012 The Android Open Source Project 3// 4// Licensed under the Apache License, Version 2.0 (the "License"); 5// you may not use this file except in compliance with the License. 6// You may obtain a copy of the License at 7// 8// http://www.apache.org/licenses/LICENSE-2.0 9// 10// Unless required by applicable law or agreed to in writing, software 11// distributed under the License is distributed on an "AS IS" BASIS, 12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13// See the License for the specific language governing permissions and 14// limitations under the License. 15// 16 17#include "shill/scope_logger.h" 18 19#include <vector> 20 21#include <base/strings/string_tokenizer.h> 22#include <base/strings/string_util.h> 23 24using base::StringTokenizer; 25using std::string; 26using std::vector; 27 28namespace shill { 29 30namespace { 31 32const int kDefaultVerboseLevel = 0; 33 34// Scope names corresponding to the scope defined by ScopeLogger::Scope. 35const char* const kScopeNames[] = { 36 "binder", 37 "cellular", 38 "connection", 39 "crypto", 40 "daemon", 41 "dbus", 42 "device", 43 "dhcp", 44 "dns", 45 "ethernet", 46 "http", 47 "httpproxy", 48 "inet", 49 "link", 50 "manager", 51 "metrics", 52 "modem", 53 "portal", 54 "power", 55 "ppp", 56 "pppoe", 57 "profile", 58 "property", 59 "resolver", 60 "route", 61 "rtnl", 62 "service", 63 "storage", 64 "task", 65 "vpn", 66 "wifi", 67 "wimax", 68}; 69 70static_assert(arraysize(kScopeNames) == ScopeLogger::kNumScopes, 71 "Scope tags do not have expected number of strings"); 72 73// ScopeLogger needs to be a 'leaky' singleton as it needs to survive to 74// handle logging till the very end of the shill process. Making ScopeLogger 75// leaky is fine as it does not need to clean up or release any resource at 76// destruction. 77base::LazyInstance<ScopeLogger>::Leaky g_scope_logger = 78 LAZY_INSTANCE_INITIALIZER; 79 80} // namespace 81 82// static 83ScopeLogger* ScopeLogger::GetInstance() { 84 return g_scope_logger.Pointer(); 85} 86 87ScopeLogger::ScopeLogger() 88 : verbose_level_(kDefaultVerboseLevel) { 89} 90 91ScopeLogger::~ScopeLogger() { 92} 93 94bool ScopeLogger::IsLogEnabled(Scope scope, int verbose_level) const { 95 return IsScopeEnabled(scope) && verbose_level <= verbose_level_; 96} 97 98bool ScopeLogger::IsScopeEnabled(Scope scope) const { 99 CHECK_GE(scope, 0); 100 CHECK_LT(scope, kNumScopes); 101 102 return scope_enabled_[scope]; 103} 104 105string ScopeLogger::GetAllScopeNames() const { 106 vector<string> names(kScopeNames, kScopeNames + arraysize(kScopeNames)); 107 return base::JoinString(names, "+"); 108} 109 110string ScopeLogger::GetEnabledScopeNames() const { 111 vector<string> names; 112 for (size_t i = 0; i < arraysize(kScopeNames); ++i) { 113 if (scope_enabled_[i]) 114 names.push_back(kScopeNames[i]); 115 } 116 return base::JoinString(names, "+"); 117} 118 119void ScopeLogger::EnableScopesByName(const string& expression) { 120 if (expression.empty()) { 121 DisableAllScopes(); 122 return; 123 } 124 125 // As described in the header file, if the first scope name in the 126 // sequence specified by |expression| is not prefixed by a plus or 127 // minus sign, it indicates that all scopes are first disabled before 128 // enabled by |expression|. 129 if (expression[0] != '+' && expression[0] != '-') 130 DisableAllScopes(); 131 132 bool enable_scope = true; 133 StringTokenizer tokenizer(expression, "+-"); 134 tokenizer.set_options(StringTokenizer::RETURN_DELIMS); 135 while (tokenizer.GetNext()) { 136 if (tokenizer.token_is_delim()) { 137 enable_scope = (tokenizer.token() == "+"); 138 continue; 139 } 140 141 if (tokenizer.token().empty()) 142 continue; 143 144 size_t i; 145 for (i = 0; i < arraysize(kScopeNames); ++i) { 146 if (tokenizer.token() == kScopeNames[i]) { 147 SetScopeEnabled(static_cast<Scope>(i), enable_scope); 148 break; 149 } 150 } 151 LOG_IF(WARNING, i == arraysize(kScopeNames)) 152 << "Unknown scope '" << tokenizer.token() << "'"; 153 } 154} 155 156void ScopeLogger::RegisterScopeEnableChangedCallback( 157 Scope scope, ScopeEnableChangedCallback callback) { 158 CHECK_GE(scope, 0); 159 CHECK_LT(scope, kNumScopes); 160 log_scope_callbacks_[scope].push_back(callback); 161} 162 163void ScopeLogger::DisableAllScopes() { 164 // Iterate over all scopes so the notification side-effect occurs. 165 for (size_t i = 0; i < arraysize(kScopeNames); ++i) { 166 SetScopeEnabled(static_cast<Scope>(i), false); 167 } 168} 169 170void ScopeLogger::SetScopeEnabled(Scope scope, bool enabled) { 171 CHECK_GE(scope, 0); 172 CHECK_LT(scope, kNumScopes); 173 174 if (scope_enabled_[scope] != enabled) { 175 for (const auto& callback : log_scope_callbacks_[scope]) { 176 callback.Run(enabled); 177 } 178 } 179 180 scope_enabled_[scope] = enabled; 181} 182 183} // namespace shill 184