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