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