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 24 using base::StringTokenizer; 25 using std::string; 26 using std::vector; 27 28 namespace shill { 29 30 namespace { 31 32 const int kDefaultVerboseLevel = 0; 33 34 // Scope names corresponding to the scope defined by ScopeLogger::Scope. 35 const 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 70 static_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. 77 base::LazyInstance<ScopeLogger>::Leaky g_scope_logger = 78 LAZY_INSTANCE_INITIALIZER; 79 80 } // namespace 81 82 // static 83 ScopeLogger* ScopeLogger::GetInstance() { 84 return g_scope_logger.Pointer(); 85 } 86 87 ScopeLogger::ScopeLogger() 88 : verbose_level_(kDefaultVerboseLevel) { 89 } 90 91 ScopeLogger::~ScopeLogger() { 92 } 93 94 bool ScopeLogger::IsLogEnabled(Scope scope, int verbose_level) const { 95 return IsScopeEnabled(scope) && verbose_level <= verbose_level_; 96 } 97 98 bool ScopeLogger::IsScopeEnabled(Scope scope) const { 99 CHECK_GE(scope, 0); 100 CHECK_LT(scope, kNumScopes); 101 102 return scope_enabled_[scope]; 103 } 104 105 string ScopeLogger::GetAllScopeNames() const { 106 vector<string> names(kScopeNames, kScopeNames + arraysize(kScopeNames)); 107 return base::JoinString(names, "+"); 108 } 109 110 string 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 119 void 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 156 void 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 163 void 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 170 void 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