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
GetInstance()83 ScopeLogger* ScopeLogger::GetInstance() {
84   return g_scope_logger.Pointer();
85 }
86 
ScopeLogger()87 ScopeLogger::ScopeLogger()
88     : verbose_level_(kDefaultVerboseLevel) {
89 }
90 
~ScopeLogger()91 ScopeLogger::~ScopeLogger() {
92 }
93 
IsLogEnabled(Scope scope,int verbose_level) const94 bool ScopeLogger::IsLogEnabled(Scope scope, int verbose_level) const {
95   return IsScopeEnabled(scope) && verbose_level <= verbose_level_;
96 }
97 
IsScopeEnabled(Scope scope) const98 bool ScopeLogger::IsScopeEnabled(Scope scope) const {
99   CHECK_GE(scope, 0);
100   CHECK_LT(scope, kNumScopes);
101 
102   return scope_enabled_[scope];
103 }
104 
GetAllScopeNames() const105 string ScopeLogger::GetAllScopeNames() const {
106   vector<string> names(kScopeNames, kScopeNames + arraysize(kScopeNames));
107   return base::JoinString(names, "+");
108 }
109 
GetEnabledScopeNames() const110 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 
EnableScopesByName(const string & expression)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 
RegisterScopeEnableChangedCallback(Scope scope,ScopeEnableChangedCallback callback)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 
DisableAllScopes()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 
SetScopeEnabled(Scope scope,bool enabled)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