• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "logger.h"
17 #include "os/thread.h"
18 #include "string_helpers.h"
19 #include "generated/base_options.h"
20 
21 #include <cstdarg>
22 #include <cstdlib>
23 #include <cstring>
24 
25 #include <fstream>
26 #include <iostream>
27 #include <string_view>
28 
29 namespace panda {
30 
31 Logger *Logger::logger = nullptr;
32 os::memory::Mutex Logger::mutex;  // NOLINT(fuchsia-statically-constructed-objects)
33 FUNC_MOBILE_LOG_PRINT mlog_buf_print = nullptr;
34 
Initialize(const base_options::Options & options)35 void Logger::Initialize(const base_options::Options &options)
36 {
37     panda::Logger::ComponentMask component_mask;
38     for (const auto &s : options.GetLogComponents()) {
39         component_mask |= Logger::ComponentMaskFromString(s);
40     }
41 
42     if (options.GetLogStream() == "std") {
43         Logger::InitializeStdLogging(Logger::LevelFromString(options.GetLogLevel()), component_mask);
44     } else if (options.GetLogStream() == "file" || options.GetLogStream() == "fast-file") {
45         const std::string &file_name = options.GetLogFile();
46         Logger::InitializeFileLogging(file_name, Logger::LevelFromString(options.GetLogLevel()), component_mask);
47     } else if (options.GetLogStream() == "dummy") {
48         Logger::InitializeDummyLogging(Logger::LevelFromString(options.GetLogLevel()), component_mask);
49     } else {
50         UNREACHABLE();
51     }
52 }
53 
~Message()54 Logger::Message::~Message()
55 {
56     if (print_system_error_) {
57         stream_ << ": " << os::Error(errno).ToString();
58     }
59 
60     Logger::Log(level_, component_, stream_.str());
61 
62     if (level_ == Level::FATAL) {
63         std::abort();
64     }
65 }
66 
GetComponentTag(Logger::Component component)67 static const char *GetComponentTag(Logger::Component component)
68 {
69 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
70 #define D(e, v, str)                         \
71     if (component == Logger::Component::e) { \
72         return str;                          \
73     }
74     LOG_COMPONENT_LIST(D)
75 #undef D
76 
77     UNREACHABLE();
78 }
79 
80 /* static */
Log(Level level,Component component,const std::string & str)81 void Logger::Log(Level level, Component component, const std::string &str)
82 {
83     if (!IsLoggingOn(level, component)) {
84         return;
85     }
86 
87     os::memory::LockHolder<os::memory::Mutex> lock(mutex);
88     if (!IsLoggingOn(level, component)) {
89         return;
90     }
91 
92     size_t nl = str.find('\n');
93     if (nl == std::string::npos) {
94         logger->LogLineInternal(level, component, str);
95         logger->WriteMobileLog(level, GetComponentTag(component), str.c_str());
96     } else {
97         size_t i = 0;
98         while (nl != std::string::npos) {
99             std::string line = str.substr(i, nl - i);
100             logger->LogLineInternal(level, component, line);
101             logger->WriteMobileLog(level, GetComponentTag(component), line.c_str());
102             i = nl + 1;
103             nl = str.find('\n', i);
104         }
105 
106         logger->LogLineInternal(level, component, str.substr(i));
107         logger->WriteMobileLog(level, GetComponentTag(component), str.substr(i).c_str());
108     }
109 }
110 
GetLevelTag(Logger::Level level)111 static const char *GetLevelTag(Logger::Level level)
112 {
113 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
114 #define D(e, v, short_str, str)      \
115     if (level == Logger::Level::e) { \
116         return short_str;            \
117     }
118     LOG_LEVEL_LIST(D)
119 #undef D
120 
121     UNREACHABLE();
122 }
123 
124 /* static */
GetPrefix(Logger::Level level,Logger::Component component)125 std::string GetPrefix(Logger::Level level, Logger::Component component)
126 {
127     // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg)
128     return helpers::string::Format("[TID %06x] %s/%s: ", os::thread::GetCurrentThreadId(), GetLevelTag(level),
129                                    GetComponentTag(component));
130 }
131 
132 /* static */
InitializeFileLogging(const std::string & log_file,Level level,ComponentMask component_mask)133 void Logger::InitializeFileLogging(const std::string &log_file, Level level, ComponentMask component_mask)
134 {
135     if (IsInitialized()) {
136         return;
137     }
138 
139     os::memory::LockHolder<os::memory::Mutex> lock(mutex);
140 
141     if (IsInitialized()) {
142         return;
143     }
144 
145     std::ofstream stream(log_file);
146     if (stream) {
147         // CODECHECK-NOLINTNEXTLINE(CPP_RULE_ID_SMARTPOINTER_INSTEADOF_ORIGINPOINTER)
148         logger = new FileLogger(std::move(stream), level, component_mask);
149     } else {
150         // CODECHECK-NOLINTNEXTLINE(CPP_RULE_ID_SMARTPOINTER_INSTEADOF_ORIGINPOINTER)
151         logger = new StderrLogger(level, component_mask);
152         // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg)
153         std::string msg = helpers::string::Format("Fallback to stderr logging: cannot open log file '%s': %s",
154                                                   log_file.c_str(), os::Error(errno).ToString().c_str());
155         logger->LogLineInternal(Level::ERROR, Component::COMMON, msg);
156     }
157 #ifdef PANDA_TARGET_UNIX
158     if (DfxController::IsInitialized() && DfxController::GetOptionValue(DfxOptionHandler::MOBILE_LOG) == 0) {
159         Logger::SetMobileLogOpenFlag(false);
160     }
161 #endif
162 }
163 
164 /* static */
InitializeStdLogging(Level level,ComponentMask component_mask)165 void Logger::InitializeStdLogging(Level level, ComponentMask component_mask)
166 {
167     if (IsInitialized()) {
168         return;
169     }
170 
171     {
172         os::memory::LockHolder<os::memory::Mutex> lock(mutex);
173 
174         if (IsInitialized()) {
175             return;
176         }
177 
178         // CODECHECK-NOLINTNEXTLINE(CPP_RULE_ID_SMARTPOINTER_INSTEADOF_ORIGINPOINTER)
179         logger = new StderrLogger(level, component_mask);
180 #ifdef PANDA_TARGET_UNIX
181         if (DfxController::IsInitialized() && DfxController::GetOptionValue(DfxOptionHandler::MOBILE_LOG) == 0) {
182             Logger::SetMobileLogOpenFlag(false);
183         }
184 #endif
185     }
186 }
187 
188 /* static */
InitializeDummyLogging(Level level,ComponentMask component_mask)189 void Logger::InitializeDummyLogging(Level level, ComponentMask component_mask)
190 {
191     if (IsInitialized()) {
192         return;
193     }
194 
195     {
196         os::memory::LockHolder<os::memory::Mutex> lock(mutex);
197 
198         if (IsInitialized()) {
199             return;
200         }
201 
202         // CODECHECK-NOLINTNEXTLINE(CPP_RULE_ID_SMARTPOINTER_INSTEADOF_ORIGINPOINTER)
203         logger = new DummyLogger(level, component_mask);
204     }
205 }
206 
207 /* static */
Destroy()208 void Logger::Destroy()
209 {
210     if (!IsInitialized()) {
211         return;
212     }
213 
214     Logger *l = nullptr;
215 
216     {
217         os::memory::LockHolder<os::memory::Mutex> lock(mutex);
218 
219         if (!IsInitialized()) {
220             return;
221         }
222 
223         l = logger;
224         logger = nullptr;
225     }
226 
227     delete l;
228 }
229 
230 /* static */
LevelFromString(std::string_view s)231 Logger::Level Logger::LevelFromString(std::string_view s)
232 {
233 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
234 #define D(e, v, short_str, str)  \
235     if (s == str) {              \
236         return Logger::Level::e; \
237     }
238     LOG_LEVEL_LIST(D)
239 #undef D
240 
241     UNREACHABLE();
242 }
243 
244 /* static */
ComponentMaskFromString(std::string_view s)245 Logger::ComponentMask Logger::ComponentMaskFromString(std::string_view s)
246 {
247 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
248 #define D(e, v, str)                                                     \
249     if (s == str) {                                                      \
250         return panda::Logger::ComponentMask().set(Logger::Component::e); \
251     }
252     LOG_COMPONENT_LIST(D)
253 #undef D
254 
255     if (s == "all") {
256         return panda::LoggerComponentMaskAll;
257     }
258 
259     UNREACHABLE();
260 }
261 
262 /* static */
StringfromDfxComponent(LogDfxComponent dfx_component)263 std::string Logger::StringfromDfxComponent(LogDfxComponent dfx_component)
264 {
265     switch (dfx_component) {
266 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
267 #define D(e, v, str)                 \
268     case Logger::LogDfxComponent::e: \
269         return str;
270         LOG_DFX_COMPONENT_LIST(D)  // CODECHECK-NOLINT(C_RULE_ID_SWITCH_INDENTATION)
271 #undef D
272         default:
273             break;
274     }
275     UNREACHABLE();
276 }
277 
278 /* static */
IsInLevelList(std::string_view s)279 bool Logger::IsInLevelList(std::string_view s)
280 {
281 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
282 #define D(e, v, short_str, str) \
283     if (s == str) {             \
284         return true;            \
285     }
286     LOG_LEVEL_LIST(D)
287 #undef D
288     return false;
289 }
290 
291 /* static */
IsInComponentList(std::string_view s)292 bool Logger::IsInComponentList(std::string_view s)
293 {
294 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
295 #define D(e, v, str) \
296     if (s == str) {  \
297         return true; \
298     }
299     LOG_COMPONENT_LIST(D)
300 #undef D
301     if (s == "all") {
302         return true;
303     }
304     return false;
305 }
306 
307 /* static */
ProcessLogLevelFromString(std::string_view s)308 void Logger::ProcessLogLevelFromString(std::string_view s)
309 {
310     if (Logger::IsInLevelList(s)) {
311         Logger::SetLevel(Logger::LevelFromString(s));
312     } else {
313         LOG(ERROR, RUNTIME) << "Unknown level " << s;
314     }
315 }
316 
317 /* static */
ProcessLogComponentsFromString(std::string_view s)318 void Logger::ProcessLogComponentsFromString(std::string_view s)
319 {
320     Logger::ResetComponentMask();
321     size_t last_pos = s.find_first_not_of(',', 0);
322     size_t pos = s.find(',', last_pos);
323     while (last_pos != std::string_view::npos) {
324         std::string_view component_str = s.substr(last_pos, pos - last_pos);
325         last_pos = s.find_first_not_of(',', pos);
326         pos = s.find(',', last_pos);
327         if (Logger::IsInComponentList(component_str)) {
328             Logger::EnableComponent(Logger::ComponentMaskFromString(component_str));
329         } else {
330             LOG(ERROR, RUNTIME) << "Unknown component " << component_str;
331         }
332     }
333 }
334 
LogLineInternal(Level level,Component component,const std::string & str)335 void FileLogger::LogLineInternal(Level level, Component component, const std::string &str)
336 {
337     std::string prefix = GetPrefix(level, component);
338     stream_ << prefix << str << std::endl << std::flush;
339 }
340 
LogLineInternal(Level level,Component component,const std::string & str)341 void StderrLogger::LogLineInternal(Level level, Component component, const std::string &str)
342 {
343     std::string prefix = GetPrefix(level, component);
344     std::cerr << prefix << str << std::endl << std::flush;
345 }
346 
347 }  // namespace panda
348