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 51namespace panda { 52 53// NOLINTNEXTLINE(cppcoreguidelines-macro-usage) 54#define LOG_COMPONENT_ELEM(D, NAME, STR) D(NAME, NAME, STR) 55 56using FUNC_MOBILE_LOG_PRINT = int (*)(int, int, const char *, const char *, const char *); 57constexpr int LOG_ID_MAIN = 0; 58extern FUNC_MOBILE_LOG_PRINT mlog_buf_print; 59 60namespace base_options { 61class Options; 62} // namespace base_options 63 64class Logger { 65public: 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: 87 Buffer() : buffer {} {} 88 89 public: 90 const char *data() const noexcept 91 { 92 return buffer.data(); 93 } 94 char *data() noexcept 95 { 96 return buffer.data(); 97 } 98 99 public: 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: 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 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 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 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 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 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 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 236 static void SetLevel(Level level) 237 { 238 ASSERT(IsInitialized()); 239 logger->level_ = level; 240 } 241 242 static Level GetLevel() 243 { 244 ASSERT(IsInitialized()); 245 return logger->level_; 246 } 247 248 static void EnableComponent(Component component) 249 { 250 ASSERT(IsInitialized()); 251 logger->component_mask_.set(component); 252 } 253 254 static void EnableComponent(const ComponentMask &component) 255 { 256 ASSERT(IsInitialized()); 257 logger->component_mask_ |= component; 258 } 259 260 static void DisableComponent(Component component) 261 { 262 ASSERT(IsInitialized()); 263 logger->component_mask_.reset(component); 264 } 265 266 static void ResetComponentMask() 267 { 268 ASSERT(IsInitialized()); 269 logger->component_mask_.reset(); 270 } 271 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 286 static bool IsInitialized() 287 { 288 return logger != nullptr; 289 } 290 291protected: 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 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 329private: 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 346static Logger::ComponentMask LoggerComponentMaskAll = ~Logger::ComponentMask(); 347 348class FileLogger : public Logger { 349protected: 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; 356 void SyncOutputResource() override {} 357 358 ~FileLogger() override = default; 359 360 NO_COPY_SEMANTIC(FileLogger); 361 NO_MOVE_SEMANTIC(FileLogger); 362 363private: 364 std::ofstream stream_; 365 366 friend Logger; 367}; 368 369class FastFileLogger : public Logger { 370protected: 371 // Uses advanced Logger constructor, so we tell to suppress all nested messages below WARNING severity 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 385private: 386 std::ofstream stream_; 387 388 friend Logger; 389}; 390 391#ifdef ENABLE_HILOG 392class HiLogger : public Logger { 393protected: 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; 397 void SyncOutputResource() override {} 398 399 ~HiLogger() override = default; 400 401 NO_COPY_SEMANTIC(HiLogger); 402 NO_MOVE_SEMANTIC(HiLogger); 403 404private: 405 std::ostringstream stream_; 406 407 friend Logger; 408}; 409#endif 410 411class StderrLogger : public Logger { 412private: 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; 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 426class DummyLogger : public Logger { 427private: 428 DummyLogger(Level level, const ComponentMask &component_mask) : Logger(level, component_mask) {} 429 430 void LogLineInternal([[maybe_unused]] Level level, [[maybe_unused]] Component component, 431 [[maybe_unused]] const std::string &str) override 432 { 433 } 434 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 445class DummyStream { 446public: 447 explicit operator bool() const 448 { 449 return true; 450 } 451}; 452 453template <class T> 454DummyStream operator<<(DummyStream s, [[maybe_unused]] const T &v) 455{ 456 return s; 457} 458 459class LogOnceHelper { 460public: 461 bool IsFirstCall() 462 { 463 flag_ >>= 1U; 464 return flag_ != 0; 465 } 466 467private: 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