• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright (c) 2021-2022 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 LIBPANDABASE_UTILS_LOGGER_H
17 #define LIBPANDABASE_UTILS_LOGGER_H
18 
19 #include "macros.h"
20 #include "os/error.h"
21 #include "os/mutex.h"
22 #include "os/thread.h"
23 
24 #include <array>
25 #include <cstdint>
26 
27 #include <bitset>
28 #include <fstream>
29 #include <map>
30 #include <string>
31 #include <sstream>
32 
33 #include <atomic>
34 
35 #ifdef ENABLE_HILOG
36 #include <hilog/log.h>
37 #endif
38 
39 namespace panda {
40 
41 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
42 #define LOG_COMPONENT_ELEM(D, NAME, STR) D(NAME, NAME, STR)
43 
44 using FUNC_MOBILE_LOG_PRINT = int (*)(int, int, const char *, const char *, const char *);
45 constexpr int LOG_ID_MAIN = 0;
46 extern FUNC_MOBILE_LOG_PRINT mlog_buf_print;
47 
48 namespace base_options {
49 class Options;
50 }  // namespace base_options
51 
52 class Logger {
53 public:
54 #include <logger_enum_gen.h>
55 
56     using ComponentMask = std::bitset<Component::LAST>;
57 
58     enum PandaLog2MobileLog : int {
59         UNKNOWN = 0,
60         DEFAULT,
61         VERBOSE,
62         DEBUG,
63         INFO,
64         WARN,
65         ERROR,
66         FATAL,
67         SILENT,
68     };
69 
70     class Buffer {
71     public:
72         constexpr static size_t BUFFER_SIZE = 4096;
73 
74     public:
Buffer()75         Buffer() : buffer {} {}
76 
77     public:
data()78         const char *data() const noexcept
79         {
80             return buffer.data();
81         }
data()82         char *data() noexcept
83         {
84             return buffer.data();
85         }
86 
87     public:
size()88         constexpr size_t size() const noexcept
89         {
90             return BUFFER_SIZE;
91         }
92 
93     public:
94         // always overwrites buffer data
95         Buffer &printf(const char *format, ...);
96 
97     public:
98         friend std::ostream &operator<<(std::ostream &os, const Buffer &b)
99         {
100             return os << b.data();
101         }
102 
103     private:
104         std::array<char, BUFFER_SIZE> buffer;
105     };
106 
107     class Message {
108     public:
Message(Level level,Component component,bool print_system_error)109         Message(Level level, Component component, bool print_system_error)
110             : level_(level), component_(component), print_system_error_(print_system_error)
111         {
112 #ifndef NDEBUG
113             Logger::LogNestingInc();
114 #endif
115         }
116 
117         ~Message();
118 
GetStream()119         std::ostream &GetStream()
120         {
121             return stream_;
122         }
123 
124     private:
125         Level level_;
126         Component component_;
127         bool print_system_error_;
128         std::ostringstream stream_;
129 
130         NO_COPY_SEMANTIC(Message);
131         NO_MOVE_SEMANTIC(Message);
132     };
133 
134     static void Initialize(const base_options::Options &options);
135 
136     static void InitializeFileLogging(const std::string &log_file, Level level, ComponentMask component_mask,
137                                       bool is_fast_logging = false);
138 #ifdef ENABLE_HILOG
139     static void InitializeHiLogging(Level level, ComponentMask component_mask);
140 #endif
141 
142     static void InitializeStdLogging(Level level, ComponentMask component_mask);
143 
144     static void InitializeDummyLogging(Level level = Level::DEBUG, ComponentMask component_mask = 0);
145 
146     static void Destroy();
147 
SetMobileLogPrintEntryPointByPtr(void * mlog_buf_print_ptr)148     static void SetMobileLogPrintEntryPointByPtr(void *mlog_buf_print_ptr)
149     {
150         mlog_buf_print = reinterpret_cast<FUNC_MOBILE_LOG_PRINT>(mlog_buf_print_ptr);
151     }
152 
153     static uint32_t GetLevelNumber(Logger::Level level);
154 
WriteMobileLog(Level level,const char * component,const char * message)155     void WriteMobileLog(Level level, const char *component, const char *message)
156     {
157         if (mlog_buf_print == nullptr || !is_mlog_opened_) {
158             return;
159         }
160         PandaLog2MobileLog mlog_level = PandaLog2MobileLog::UNKNOWN;
161         switch (level) {
162             case Level::DEBUG:
163                 mlog_level = PandaLog2MobileLog::DEBUG;
164                 break;
165             case Level::INFO:
166                 mlog_level = PandaLog2MobileLog::INFO;
167                 break;
168             case Level::ERROR:
169                 mlog_level = PandaLog2MobileLog::ERROR;
170                 break;
171             case Level::FATAL:
172                 mlog_level = PandaLog2MobileLog::FATAL;
173                 break;
174             case Level::WARNING:
175                 mlog_level = PandaLog2MobileLog::WARN;
176                 break;
177             default:
178                 UNREACHABLE();
179         }
180         std::string panda_component = "Ark " + std::string(component);
181         mlog_buf_print(LOG_ID_MAIN, mlog_level, panda_component.c_str(), "%s", message);
182     }
183 
IsLoggingOn(Level level,Component component)184     static bool IsLoggingOn(Level level, Component component)
185     {
186         return IsInitialized() && level <= logger->level_ &&
187                (logger->component_mask_.test(component) || level == Level::FATAL);
188     }
189 
IsLoggingOnOrAbort(Level level,Component component)190     static bool IsLoggingOnOrAbort(Level level, Component component)
191     {
192         if (IsLoggingOn(level, component)) {
193             return true;
194         }
195 
196         if (level == Level::FATAL) {
197             std::abort();
198         }
199 
200         return false;
201     }
202 
203 #ifndef NDEBUG
204     static void LogNestingInc();
205     static void LogNestingDec();
206     static bool IsMessageSuppressed([[maybe_unused]] Level level, [[maybe_unused]] Component component);
207 #endif
208 
209     static void Log(Level level, Component component, const std::string &str);
210 
Sync()211     static void Sync()
212     {
213         if (IsInitialized()) {
214             logger->SyncOutputResource();
215         }
216     }
217 
218     static Level LevelFromString(std::string_view s);
219 
220     static ComponentMask ComponentMaskFromString(std::string_view s);
221 
222     static std::string StringfromDfxComponent(LogDfxComponent dfx_component);
223 
SetLevel(Level level)224     static void SetLevel(Level level)
225     {
226         ASSERT(IsInitialized());
227         logger->level_ = level;
228     }
229 
GetLevel()230     static Level GetLevel()
231     {
232         ASSERT(IsInitialized());
233         return logger->level_;
234     }
235 
EnableComponent(Component component)236     static void EnableComponent(Component component)
237     {
238         ASSERT(IsInitialized());
239         logger->component_mask_.set(component);
240     }
241 
EnableComponent(ComponentMask component)242     static void EnableComponent(ComponentMask component)
243     {
244         ASSERT(IsInitialized());
245         logger->component_mask_ |= component;
246     }
247 
DisableComponent(Component component)248     static void DisableComponent(Component component)
249     {
250         ASSERT(IsInitialized());
251         logger->component_mask_.reset(component);
252     }
253 
ResetComponentMask()254     static void ResetComponentMask()
255     {
256         ASSERT(IsInitialized());
257         logger->component_mask_.reset();
258     }
259 
SetMobileLogOpenFlag(bool is_mlog_opened)260     static void SetMobileLogOpenFlag(bool is_mlog_opened)
261     {
262         ASSERT(IsInitialized());
263         logger->is_mlog_opened_ = is_mlog_opened;
264     }
265 
266     static bool IsInLevelList(std::string_view s);
267 
268     static bool IsInComponentList(std::string_view s);
269 
270     static void ProcessLogLevelFromString(std::string_view s);
271 
272     static void ProcessLogComponentsFromString(std::string_view s);
273 
IsInitialized()274     static bool IsInitialized()
275     {
276         return logger != nullptr;
277     }
278 
279 protected:
Logger(Level level,ComponentMask component_mask)280     Logger(Level level, ComponentMask component_mask)
281         : level_(level),
282           component_mask_(component_mask)
283 #ifndef NDEBUG
284           ,
285           // Means all the LOGs are allowed just as usual
286           nested_allowed_level_(Level::LAST)
287 #endif
288     {
289     }
290 
Logger(Level level,ComponentMask component_mask,Level nested_allowed_level)291     Logger(Level level, ComponentMask component_mask, [[maybe_unused]] Level nested_allowed_level)
292         : level_(level),
293           component_mask_(component_mask)
294 #ifndef NDEBUG
295           ,
296           nested_allowed_level_(nested_allowed_level)
297 #endif
298     {
299     }
300 
301     virtual void LogLineInternal(Level level, Component component, const std::string &str) = 0;
302 
303     /**
304      * Flushes all the output buffers of LogLineInternal to the output resources
305      * Sometimes nothinig shall be done, if LogLineInternal flushes everything by itself statelessl
306      */
307     virtual void SyncOutputResource() = 0;
308 
309     virtual ~Logger() = default;
310 
311     static Logger *logger;
312 
313     static os::memory::Mutex mutex;
314 
315     static thread_local int nesting;
316 
317 private:
318     Level level_;
319     ComponentMask component_mask_;
320 #ifndef NDEBUG
321     // These are utilized by Fast* logger types.
322     // For every thread, we trace events of staring shifting to a log (<<) and finishing doing it,
323     // incrementing a log invocation depth variable bound to a thread, or decrementing it correspondingly.
324     // Such variables we're doing as thread-local.
325     // All the LOGs with levels < nested_allowed_level_ are only allowed to have depth of log == 1
326     Level nested_allowed_level_;  // Log level to suppress LOG triggering within << to another LOG
327 #endif
328     bool is_mlog_opened_ {true};
329 
330     NO_COPY_SEMANTIC(Logger);
331     NO_MOVE_SEMANTIC(Logger);
332 };
333 
334 static Logger::ComponentMask LoggerComponentMaskAll = ~Logger::ComponentMask();
335 
336 class FileLogger : public Logger {
337 protected:
FileLogger(std::ofstream && stream,Level level,ComponentMask component_mask)338     FileLogger(std::ofstream &&stream, Level level, ComponentMask component_mask)
339         : Logger(level, component_mask), stream_(std::forward<std::ofstream>(stream))
340     {
341     }
342 
343     void LogLineInternal(Level level, Component component, const std::string &str) override;
SyncOutputResource()344     void SyncOutputResource() override {}
345 
346     ~FileLogger() override = default;
347 
348     NO_COPY_SEMANTIC(FileLogger);
349     NO_MOVE_SEMANTIC(FileLogger);
350 
351 private:
352     std::ofstream stream_;
353 
354     friend Logger;
355 };
356 
357 class FastFileLogger : public Logger {
358 protected:
359     // Uses advanced Logger constructor, so we tell to suppress all nested messages below WARNING severity
FastFileLogger(std::ofstream && stream,Level level,ComponentMask component_mask)360     FastFileLogger(std::ofstream &&stream, Level level, ComponentMask component_mask)
361         : Logger(level, component_mask, Logger::Level::WARNING), stream_(std::forward<std::ofstream>(stream))
362     {
363     }
364 
365     void LogLineInternal(Level level, Component component, const std::string &str) override;
366     void SyncOutputResource() override;
367 
368     ~FastFileLogger() override = default;
369 
370     NO_COPY_SEMANTIC(FastFileLogger);
371     NO_MOVE_SEMANTIC(FastFileLogger);
372 
373 private:
374     std::ofstream stream_;
375 
376     friend Logger;
377 };
378 
379 #ifdef ENABLE_HILOG
380 class HiLogger : public Logger {
381 protected:
HiLogger(Level level,ComponentMask component_mask)382     HiLogger(Level level, ComponentMask component_mask) : Logger(level, component_mask) {}
383 
384     void LogLineInternal(Level level, Component component, const std::string &str) override;
SyncOutputResource()385     void SyncOutputResource() override {}
386 
387     ~HiLogger() override = default;
388 
389     NO_COPY_SEMANTIC(HiLogger);
390     NO_MOVE_SEMANTIC(HiLogger);
391 
392 private:
393     std::ostringstream stream_;
394     constexpr static unsigned int ARK_DOMAIN = 0xD003F00;
395     constexpr static auto TAG = "ArkCompiler";
396     constexpr static OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, ARK_DOMAIN, TAG};
397 
398     friend Logger;
399 };
400 #endif
401 
402 class StderrLogger : public Logger {
403 private:
StderrLogger(Level level,ComponentMask component_mask)404     StderrLogger(Level level, ComponentMask component_mask) : Logger(level, component_mask) {}
405 
406     void LogLineInternal(Level level, Component component, const std::string &str) override;
SyncOutputResource()407     void SyncOutputResource() override {}
408 
409     friend Logger;
410 
411     ~StderrLogger() override = default;
412 
413     NO_COPY_SEMANTIC(StderrLogger);
414     NO_MOVE_SEMANTIC(StderrLogger);
415 };
416 
417 class DummyLogger : public Logger {
418 private:
DummyLogger(Level level,ComponentMask component_mask)419     DummyLogger(Level level, ComponentMask component_mask) : Logger(level, component_mask) {}
420 
LogLineInternal(Level level,Component component,const std::string & str)421     void LogLineInternal([[maybe_unused]] Level level, [[maybe_unused]] Component component,
422                          [[maybe_unused]] const std::string &str) override
423     {
424     }
425 
SyncOutputResource()426     void SyncOutputResource() override {}
427 
428     friend Logger;
429 
430     ~DummyLogger() override = default;
431 
432     NO_COPY_SEMANTIC(DummyLogger);
433     NO_MOVE_SEMANTIC(DummyLogger);
434 };
435 
436 class DummyStream {
437 public:
438     explicit operator bool() const
439     {
440         return true;
441     }
442 };
443 
444 template <class T>
445 DummyStream operator<<(DummyStream s, [[maybe_unused]] const T &v)
446 {
447     return s;
448 }
449 
450 class LogOnceHelper {
451 public:
IsFirstCall()452     bool IsFirstCall()
453     {
454         flag_ >>= 1U;
455         return flag_ != 0;
456     }
457 
458 private:
459     uint8_t flag_ = 0x03;
460 };
461 
462 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
463 #define LOG_ONCE_HELPER() static LogOnceHelper MERGE_WORDS(log_once_helper, __LINE__);
464 
465 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
466 #define LOG_ONCE(level, component) \
467     LOG_ONCE_HELPER()              \
468     MERGE_WORDS(log_once_helper, __LINE__).IsFirstCall() && LOG(level, component)
469 
470 #ifndef NDEBUG
471 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
472 #define _LOG_SUPPRESSION_CHECK(level, component) \
473     !panda::Logger::IsMessageSuppressed(panda::Logger::Level::level, panda::Logger::Component::component)
474 #else
475 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
476 #define _LOG_SUPPRESSION_CHECK(level, component) true
477 #endif
478 
479 // Explicit namespace is specified to allow using the logger out of panda namespace.
480 // For example, in the main function.
481 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
482 #define _LOG(level, component, p)                                                                          \
483     panda::Logger::IsLoggingOnOrAbort(panda::Logger::Level::level, panda::Logger::Component::component) && \
484         _LOG_SUPPRESSION_CHECK(level, component) &&                                                        \
485         panda::Logger::Message(panda::Logger::Level::level, panda::Logger::Component::component, p).GetStream()
486 
487 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
488 #define LOG(level, component) _LOG_##level(component, false)
489 
490 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
491 #define GET_LOG_STREAM(level, component) \
492     panda::Logger::Message(panda::Logger::Level::level, panda::Logger::Component::component, false).GetStream()
493 
494 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
495 #define PLOG(level, component) _LOG_##level(component, true)
496 
497 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
498 #define LOG_IF(cond, level, component) (cond) && LOG(level, component)
499 
500 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
501 #define PLOG_IF(cond, level, component) (cond) && PLOG(level, component)
502 
503 #ifndef NDEBUG
504 
505 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
506 #define _LOG_DEBUG(component, p) _LOG(DEBUG, component, p)
507 
508 #else
509 
510 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
511 #define _LOG_DEBUG(component, p) false && panda::DummyStream()
512 
513 #endif
514 
515 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
516 #define _LOG_INFO(component, p) _LOG(INFO, component, p)
517 
518 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
519 #define _LOG_WARNING(component, p) _LOG(WARNING, component, p)
520 
521 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
522 #define _LOG_ERROR(component, p) _LOG(ERROR, component, p)
523 
524 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
525 #define _LOG_FATAL(component, p) _LOG(FATAL, component, p)
526 
527 }  // namespace panda
528 
529 #endif  // LIBPANDABASE_UTILS_LOGGER_H
530