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