• 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 #ifndef PANDA_LIBPANDABASE_UTILS_LOGGER_H_
17 #define PANDA_LIBPANDABASE_UTILS_LOGGER_H_
18 
19 #include "macros.h"
20 #include "os/error.h"
21 #include "os/mutex.h"
22 #include "utils/dfx.h"
23 
24 #include <cstdint>
25 
26 #include <fstream>
27 #include <string>
28 #include <sstream>
29 #include <bitset>
30 
31 #include <atomic>
32 
33 namespace panda {
34 
35 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
36 #define LOG_COMPONENT_ELEM(D, NAME, STR) D(NAME, NAME, STR)
37 
38 using FUNC_MOBILE_LOG_PRINT = int (*)(int, int, const char *, const char *, const char *);
39 static constexpr int LOG_ID_MAIN = 0;
40 extern FUNC_MOBILE_LOG_PRINT mlog_buf_print;
41 
42 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
43 #define LOG_COMPONENT_LIST(D)                              \
44     LOG_COMPONENT_ELEM(D, ALLOC, "alloc")                  \
45     LOG_COMPONENT_ELEM(D, ALLOC_OBJECT, "alloc-obj")       \
46     LOG_COMPONENT_ELEM(D, ASSEMBLER, "assembler")          \
47     LOG_COMPONENT_ELEM(D, CLASS_LINKER, "classlinker")     \
48     LOG_COMPONENT_ELEM(D, COMMON, "common")                \
49     LOG_COMPONENT_ELEM(D, GC, "gc")                        \
50     LOG_COMPONENT_ELEM(D, GC_TRIGGER, "gc_trigger")        \
51     LOG_COMPONENT_ELEM(D, REF_PROC, "reference_processor") \
52     LOG_COMPONENT_ELEM(D, INTERPRETER, "interpreter")      \
53     LOG_COMPONENT_ELEM(D, FUZZER, "fuzzer")                \
54     LOG_COMPONENT_ELEM(D, PANDAFILE, "pandafile")          \
55     LOG_COMPONENT_ELEM(D, MEMORYPOOL, "memorypool")        \
56     LOG_COMPONENT_ELEM(D, RUNTIME, "runtime")              \
57     LOG_COMPONENT_ELEM(D, TRACE, "trace")                  \
58     LOG_COMPONENT_ELEM(D, DPROF, "dprof")                  \
59     LOG_COMPONENT_ELEM(D, ECMASCRIPT, "ecmascript")        \
60     LOG_COMPONENT_ELEM(D, DEBUGGER, "debugger")            \
61     LOG_COMPONENT_ELEM(D, TOOLING, "tooling")              \
62     LOG_COMPONENT_ELEM(D, INTEROP, "interop")              \
63     LOG_COMPONENT_ELEM(D, VERIFIER, "verifier")            \
64     LOG_COMPONENT_ELEM(D, DISASSEMBLER, "disassembler")    \
65     LOG_COMPONENT_ELEM(D, ZIPARCHIVE, "ziparchive")        \
66     LOG_COMPONENT_ELEM(D, EVENTS, "events")                \
67     LOG_COMPONENT_ELEM(D, DFX, "dfx")                      \
68     LOG_COMPONENT_ELEM(D, SCHEDULER, "scheduler")
69 
70 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
71 #define LOG_LEVEL_LIST(D)            \
72     D(FATAL, 0x00, "F", "fatal")     \
73     D(ERROR, 0x01, "E", "error")     \
74     D(WARNING, 0x02, "W", "warning") \
75     D(INFO, 0x03, "I", "info")       \
76     D(DEBUG, 0x04, "D", "debug")
77 
78 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
79 #define LOG_DFX_COMPONENT_LIST(D) \
80     D(COMMON, 0x00, "common")     \
81     D(SIGNAL, 0x01, "signal")
82 
83 namespace base_options {
84 class Options;
85 }  // namespace base_options
86 
87 class Logger {
88 public:
89     enum Component : uint32_t {
90 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
91 #define D(e, v, str) e,
92         LOG_COMPONENT_LIST(D)
93 #undef D
94             LAST
95     };
96 
97     using ComponentMask = std::bitset<Component::LAST>;
98 
99     enum class Level : uint8_t {
100 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
101 #define D(e, v, short_str, str) e = v,
102         LOG_LEVEL_LIST(D)
103 #undef D
104     };
105 
106     enum class LogDfxComponent : uint8_t {
107 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
108 #define D(e, v, str) e = v,
109         LOG_DFX_COMPONENT_LIST(D)
110 #undef D
111     };
112 
113     enum PandaLog2MobileLog : int {
114         UNKNOWN = 0,
115         DEFAULT,
116         VERBOSE,
117         DEBUG,
118         INFO,
119         WARN,
120         ERROR,
121         FATAL,
122         SILENT,
123     };
124 
125     class Message {
126     public:
Message(Level level,Component component,bool print_system_error)127         Message(Level level, Component component, bool print_system_error)
128             : level_(level), component_(component), print_system_error_(print_system_error)
129         {
130         }
131 
132         ~Message();
133 
GetStream()134         std::ostream &GetStream()
135         {
136             return stream_;
137         }
138 
139     private:
140         Level level_;
141         Component component_;
142         bool print_system_error_;
143         std::ostringstream stream_;
144 
145         NO_COPY_SEMANTIC(Message);
146         NO_MOVE_SEMANTIC(Message);
147     };
148 
149     static void Initialize(const base_options::Options &options);
150 
151     static void InitializeFileLogging(const std::string &log_file, Level level, ComponentMask component_mask);
152 
153     static void InitializeStdLogging(Level level, ComponentMask component_mask);
154 
155     static void InitializeDummyLogging(Level level = Level::DEBUG, ComponentMask component_mask = 0);
156 
157     static void Destroy();
158 
SetMobileLogPrintEntryPointByPtr(void * mlog_buf_print_ptr)159     static void SetMobileLogPrintEntryPointByPtr(void *mlog_buf_print_ptr)
160     {
161         mlog_buf_print = reinterpret_cast<FUNC_MOBILE_LOG_PRINT>(mlog_buf_print_ptr);
162     }
163 
GetLevelNumber(Logger::Level level)164     static uint32_t GetLevelNumber(Logger::Level level)
165     {
166         switch (level) {
167             // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
168 #define D(e, v, short_str, str) \
169     case Logger::Level::e:      \
170         return v;
171             LOG_LEVEL_LIST(D)
172 #undef D
173             default:
174                 break;
175         };
176 
177         UNREACHABLE();
178         return 0;
179     }
180 
WriteMobileLog(Level level,const char * component,const char * message)181     void WriteMobileLog(Level level, const char *component, const char *message)
182     {
183         if (mlog_buf_print == nullptr || !is_mlog_opened_) {
184             return;
185         }
186         PandaLog2MobileLog mlog_level = PandaLog2MobileLog::UNKNOWN;
187         switch (level) {
188             case Level::DEBUG:
189                 mlog_level = PandaLog2MobileLog::DEBUG;
190                 break;
191             case Level::INFO:
192                 mlog_level = PandaLog2MobileLog::INFO;
193                 break;
194             case Level::ERROR:
195                 mlog_level = PandaLog2MobileLog::ERROR;
196                 break;
197             case Level::FATAL:
198                 mlog_level = PandaLog2MobileLog::FATAL;
199                 break;
200             case Level::WARNING:
201                 mlog_level = PandaLog2MobileLog::WARN;
202                 break;
203             default:
204                 UNREACHABLE();
205         }
206         std::string panda_component = "Ark " + std::string(component);
207         mlog_buf_print(LOG_ID_MAIN, mlog_level, panda_component.c_str(), "%s", message);
208     }
209 
IsLoggingOn(Level level,Component component)210     static bool IsLoggingOn(Level level, Component component)
211     {
212         return IsInitialized() && level <= logger->level_ && (logger->component_mask_.test(component));
213     }
214 
IsLoggingOnOrAbort(Level level,Component component)215     static bool IsLoggingOnOrAbort(Level level, Component component)
216     {
217         if (IsLoggingOn(level, component)) {
218             return true;
219         }
220 
221         if (level == Level::FATAL) {
222             std::abort();
223         }
224 
225         return false;
226     }
227 
IsLoggingDfxOn()228     static bool IsLoggingDfxOn()
229     {
230         if (!DfxController::IsInitialized() || !IsInitialized()) {
231             return false;
232         }
233         return (DfxController::GetOptionValue(DfxOptionHandler::DFXLOG) == 1);
234     }
235 
236     static void Log(Level level, Component component, const std::string &str);
237 
238     static Level LevelFromString(std::string_view s);
239 
240     static ComponentMask ComponentMaskFromString(std::string_view s);
241 
242     static std::string StringfromDfxComponent(LogDfxComponent dfx_component);
243 
SetLevel(Level level)244     static void SetLevel(Level level)
245     {
246         ASSERT(IsInitialized());
247         logger->level_ = level;
248     }
249 
GetLevel()250     static Level GetLevel()
251     {
252         ASSERT(IsInitialized());
253         return logger->level_;
254     }
255 
EnableComponent(Component component)256     static void EnableComponent(Component component)
257     {
258         ASSERT(IsInitialized());
259         logger->component_mask_.set(component);
260     }
261 
EnableComponent(ComponentMask component)262     static void EnableComponent(ComponentMask component)
263     {
264         ASSERT(IsInitialized());
265         logger->component_mask_ |= component;
266     }
267 
DisableComponent(Component component)268     static void DisableComponent(Component component)
269     {
270         ASSERT(IsInitialized());
271         logger->component_mask_.reset(component);
272     }
273 
ResetComponentMask()274     static void ResetComponentMask()
275     {
276         ASSERT(IsInitialized());
277         logger->component_mask_.reset();
278     }
279 
SetMobileLogOpenFlag(bool is_mlog_opened)280     static void SetMobileLogOpenFlag(bool is_mlog_opened)
281     {
282         ASSERT(IsInitialized());
283         logger->is_mlog_opened_ = is_mlog_opened;
284     }
285 
286     static bool IsInLevelList(std::string_view s);
287 
288     static bool IsInComponentList(std::string_view s);
289 
290     static void ProcessLogLevelFromString(std::string_view s);
291 
292     static void ProcessLogComponentsFromString(std::string_view s);
293 
IsInitialized()294     static bool IsInitialized()
295     {
296         return logger != nullptr;
297     }
298 
299 protected:
Logger(Level level,ComponentMask component_mask)300     Logger(Level level, ComponentMask component_mask) : level_(level), component_mask_(component_mask) {}
301 
302     virtual void LogLineInternal(Level level, Component component, const std::string &str) = 0;
303 
304     virtual ~Logger() = default;
305 
306     static Logger *logger;
307 
308     static os::memory::Mutex mutex;
309 
310 private:
311     Level level_;
312     ComponentMask component_mask_;
313     bool is_mlog_opened_ {true};
314 
315     NO_COPY_SEMANTIC(Logger);
316     NO_MOVE_SEMANTIC(Logger);
317 };
318 
319 static Logger::ComponentMask LoggerComponentMaskAll = ~Logger::ComponentMask();
320 
321 class FileLogger : public Logger {
322 protected:
FileLogger(std::ofstream && stream,Level level,ComponentMask component_mask)323     FileLogger(std::ofstream &&stream, Level level, ComponentMask component_mask)
324         : Logger(level, component_mask), stream_(std::forward<std::ofstream>(stream))
325     {
326     }
327 
328     void LogLineInternal(Level level, Component component, const std::string &str) override;
329 
330     ~FileLogger() override = default;
331 
332     NO_COPY_SEMANTIC(FileLogger);
333     NO_MOVE_SEMANTIC(FileLogger);
334 
335 private:
336     std::ofstream stream_;
337 
338     friend Logger;
339 };
340 
341 class StderrLogger : public Logger {
342 private:
StderrLogger(Level level,ComponentMask component_mask)343     StderrLogger(Level level, ComponentMask component_mask) : Logger(level, component_mask) {}
344 
345     void LogLineInternal(Level level, Component component, const std::string &str) override;
346 
347     friend Logger;
348 
349     ~StderrLogger() override = default;
350 
351     NO_COPY_SEMANTIC(StderrLogger);
352     NO_MOVE_SEMANTIC(StderrLogger);
353 };
354 
355 class DummyLogger : public Logger {
356 private:
DummyLogger(Level level,ComponentMask component_mask)357     DummyLogger(Level level, ComponentMask component_mask) : Logger(level, component_mask) {}
358 
LogLineInternal(Level level,Component component,const std::string & str)359     void LogLineInternal([[maybe_unused]] Level level, [[maybe_unused]] Component component,
360                          [[maybe_unused]] const std::string &str) override
361     {
362     }
363 
364     friend Logger;
365 
366     ~DummyLogger() override = default;
367 
368     NO_COPY_SEMANTIC(DummyLogger);
369     NO_MOVE_SEMANTIC(DummyLogger);
370 };
371 
372 class DummyStream {
373 public:
374     explicit operator bool() const
375     {
376         return true;
377     }
378 };
379 
380 template <class T>
381 DummyStream operator<<(DummyStream s, [[maybe_unused]] const T &v)
382 {
383     return s;
384 }
385 
386 class LogOnceHelper {
387 public:
IsFirstCall()388     bool IsFirstCall()
389     {
390         flag_ >>= 1U;
391         return flag_ != 0;
392     }
393 
394 private:
395     uint8_t flag_ = 0x03;
396 };
397 
398 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
399 #define LOG_ONCE_HELPER() static LogOnceHelper MERGE_WORDS(log_once_helper, __LINE__);
400 
401 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
402 #define LOG_ONCE(level, component) \
403     LOG_ONCE_HELPER()              \
404     MERGE_WORDS(log_once_helper, __LINE__).IsFirstCall() && LOG(level, component)
405 
406 // Explicit namespace is specified to allow using the logger out of panda namespace.
407 // For exmaple, in the main function.
408 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
409 #define _LOG(level, component, p)                                                                          \
410     panda::Logger::IsLoggingOnOrAbort(panda::Logger::Level::level, panda::Logger::Component::component) && \
411         panda::Logger::Message(panda::Logger::Level::level, panda::Logger::Component::component, p).GetStream()
412 
413 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
414 #define LOG(level, component) _LOG_##level(component, false)
415 
416 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
417 #define LOG_DFX(dfx_component)                                                                     \
418     panda::Logger::IsLoggingDfxOn() &&                                                             \
419         panda::Logger::Message(panda::Logger::Level::ERROR, panda::Logger::DFX, false).GetStream() \
420             << panda::Logger::StringfromDfxComponent(panda::Logger::LogDfxComponent::dfx_component) << " log:"
421 
422 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
423 #define GET_LOG_STREAM(level, component) \
424     panda::Logger::Message(panda::Logger::Level::level, panda::Logger::Component::component, false).GetStream()
425 
426 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
427 #define PLOG(level, component) _LOG_##level(component, true)
428 
429 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
430 #define LOG_IF(cond, level, component) (cond) && LOG(level, component)
431 
432 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
433 #define PLOG_IF(cond, level, component) (cond) && PLOG(level, component)
434 
435 #ifndef NDEBUG
436 
437 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
438 #define _LOG_DEBUG(component, p) _LOG(DEBUG, component, p)
439 
440 #else
441 
442 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
443 #define _LOG_DEBUG(component, p) false && panda::DummyStream()
444 
445 #endif
446 
447 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
448 #define _LOG_INFO(component, p) _LOG(INFO, component, p)
449 
450 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
451 #define _LOG_WARNING(component, p) _LOG(WARNING, component, p)
452 
453 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
454 #define _LOG_ERROR(component, p) _LOG(ERROR, component, p)
455 
456 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
457 #define _LOG_FATAL(component, p) _LOG(FATAL, component, p)
458 
459 }  // namespace panda
460 
461 #endif  // PANDA_LIBPANDABASE_UTILS_LOGGER_H_
462