Logging.h (5152B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- 2 * vim: set ts=8 sts=2 et sw=2 tw=80: 3 * This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 // An experimental logging interface for connecting the JS Engine to some 8 // (*cough*Gecko*cough*) consumer. 9 10 #ifndef _js_vm_Logging_h_ 11 #define _js_vm_Logging_h_ 12 13 #include "mozilla/Assertions.h" 14 #include "mozilla/LoggingCore.h" 15 16 #include "jit/JitSpewer.h" 17 #include "js/experimental/LoggingInterface.h" 18 19 struct JSContext; 20 21 namespace js { 22 23 using mozilla::LogLevel; 24 25 // [SMDOC] js::LogModule 26 // 27 // js::LogModule is the underlying type used for JS_LOG. 28 // 29 // To support declaring these statically, while simultaneously supporting the 30 // initialization of the interfaces via a callback, each instance of LogModule 31 // is registered in a module register (logModuleRegistry), which updates 32 // the module interface for each log module. 33 // 34 // Log modules are declared below using a Macro to support the metaprogramming 35 // required around their storage an initialization. 36 class LogModule { 37 public: 38 explicit constexpr LogModule(const char* name) : name(name) { 39 MOZ_ASSERT(name); 40 } 41 42 // Return true iff we should log a message at this level. 43 inline bool shouldLog(mozilla::LogLevel level) const { 44 if (!isSetup()) { 45 return false; 46 } 47 48 return *levelPtr >= level; 49 } 50 51 // Initialize all LogModules to speak with the provided interface. 52 [[nodiscard]] static bool initializeAll(const JS::LoggingInterface iface); 53 54 public: 55 // Public as it's used by the macro below, and we don't need a 56 // forwarding interface. 57 mutable JS::LoggingInterface interface{}; 58 59 // Opaque logger obtained via the interface; also public for macro useage. 60 mutable JS::OpaqueLogger logger{}; 61 62 // Name of this logger 63 const char* name{}; 64 65 private: 66 // Is this logger ready to be used. 67 inline bool isSetup() const { return interface.isComplete() && logger; } 68 69 // Initialize this Log module 70 bool initialize(const JS::LoggingInterface iface) const { 71 // Grab a local copy of the iface. 72 interface = iface; 73 MOZ_ASSERT(iface.isComplete()); 74 logger = iface.getLoggerByName(name); 75 if (!logger) { 76 return false; 77 } 78 79 levelPtr = &iface.getLevelRef(logger); 80 return true; 81 } 82 83 // Used to fast-path check if we should log. 84 mutable mozilla::AtomicLogLevel* levelPtr{}; 85 }; 86 87 #define FOR_EACH_JS_LOG_MODULE(_) \ 88 _(debug) /* A predefined log module for casual debugging */ \ 89 _(wasmPerf) /* Wasm performance statistics */ \ 90 _(wasmApi) /* Wasm JS-API tracing */ \ 91 _(fuseInvalidation) /* Invalidation triggered by a fuse */ \ 92 _(thenable) /* Thenable on standard proto*/ \ 93 _(startup) /* engine startup logging */ \ 94 _(teleporting) /* Shape Teleporting */ \ 95 _(selfHosted) /* self-hosted script logging */ \ 96 _(gc) /* The garbage collector */ \ 97 _(mtq) /* MicroTask queue */ \ 98 JITSPEW_CHANNEL_LIST(_) /* A module for each JitSpew channel. */ 99 100 // Declare Log modules 101 #define DECLARE_MODULE(X) inline constexpr LogModule X##Module(#X); 102 103 FOR_EACH_JS_LOG_MODULE(DECLARE_MODULE); 104 105 #undef DECLARE_MODULE 106 107 // By default JS_LOGGING is enabled; but if we would like this become 108 // conditional this file-internal macro can be used to accomplish that. 109 #define JS_LOGGING 1 110 111 // The core logging macro for the JS Engine. 112 #ifdef JS_LOGGING 113 # define JS_SHOULD_LOG(name, log_level) \ 114 name##Module.shouldLog(LogLevel::log_level) 115 116 # define JS_LOG(name, log_level, ...) \ 117 do { \ 118 if (name##Module.shouldLog(LogLevel::log_level)) { \ 119 name##Module.interface.logPrint(name##Module.logger, \ 120 LogLevel::log_level, __VA_ARGS__); \ 121 } \ 122 } while (0); 123 # define JS_LOG_FMT(name, log_level, fmt, ...) \ 124 do { \ 125 if (name##Module.shouldLog(LogLevel::log_level)) { \ 126 name##Module.interface.logPrintFmt(name##Module.logger, \ 127 LogLevel::log_level, \ 128 FMT_STRING(fmt), ##__VA_ARGS__); \ 129 } \ 130 } while (0); 131 #else 132 # define JS_LOG(module, log_level, ...) 133 # define JS_LOG_FMT(module, log_level, fmt, ...) 134 #endif 135 136 #undef JS_LOGGING 137 138 } // namespace js 139 140 #endif /* _js_vm_Logging_h_ */