diff --git a/js/public/experimental/LoggingInterface.h b/js/public/experimental/LoggingInterface.h index 28fd60cfe203..4ee3c13f3846 100644 --- a/js/public/experimental/LoggingInterface.h +++ b/js/public/experimental/LoggingInterface.h @@ -13,6 +13,7 @@ #include "mozilla/LoggingCore.h" #include "jstypes.h" +#include "fmt/format.h" #include "js/GCAPI.h" struct JSContext; @@ -55,6 +56,9 @@ struct LoggingInterface { const char* aFmt, va_list ap) MOZ_FORMAT_PRINTF(3, 0) = nullptr; + void (*logPrintFMT)(const OpaqueLogger aModule, mozilla::LogLevel aLevel, + fmt::string_view, fmt::format_args); + // Return a reference to the provided OpaqueLogger's level ref; Implementation // wise this can be a small violation of encapsulation but is intended to help // ensure that we can build lightweight logging without egregious costs to @@ -71,6 +75,13 @@ struct LoggingInterface { va_end(ap); } + template + void logPrintFmt(const OpaqueLogger aModule, mozilla::LogLevel aLevel, + fmt::format_string aFmt, T&&... aArgs) { + JS::AutoSuppressGCAnalysis suppress; + this->logPrintFMT(aModule, aLevel, aFmt, fmt::make_format_args(aArgs...)); + } + // Used to ensure that before we use an interface, it's successfully been // completely filled in. bool isComplete() const { diff --git a/js/src/shell/js.cpp b/js/src/shell/js.cpp index 8ec834213d53..db8cae300c62 100644 --- a/js/src/shell/js.cpp +++ b/js/src/shell/js.cpp @@ -68,6 +68,7 @@ #include "jsapi.h" #include "jsfriendapi.h" #include "jstypes.h" +#include "fmt/format.h" #ifndef JS_WITHOUT_NSPR # include "prerror.h" # include "prlink.h" @@ -384,8 +385,15 @@ void LogPrintVA(const JS::OpaqueLogger logger, mozilla::LogLevel level, fprintf(stderr, "\n"); } +void LogPrintFmt(const JS::OpaqueLogger logger, mozilla::LogLevel level, + fmt::string_view fmt, fmt::format_args args) { + ShellLogModule* mod = static_cast(logger); + fmt::print(stderr, FMT_STRING("[{}] {}\n"), mod->name, + fmt::vformat(fmt, args)); +} + JS::LoggingInterface shellLoggingInterface = {GetLoggerByName, LogPrintVA, - GetLevelRef}; + LogPrintFmt, GetLevelRef}; static void ToLower(const char* src, char* dest, size_t len) { for (size_t c = 0; c < len; c++) { diff --git a/js/src/vm/Logging.h b/js/src/vm/Logging.h index fca739fa8465..7f09579d4e85 100644 --- a/js/src/vm/Logging.h +++ b/js/src/vm/Logging.h @@ -113,8 +113,17 @@ FOR_EACH_JS_LOG_MODULE(DECLARE_MODULE); LogLevel::log_level, __VA_ARGS__); \ } \ } while (0); +# define JS_LOG_FMT(name, log_level, fmt, ...) \ + do { \ + if (name##Module.shouldLog(LogLevel::log_level)) { \ + name##Module.interface.logPrintFmt(name##Module.logger, \ + LogLevel::log_level, \ + FMT_STRING(fmt), ##__VA_ARGS__); \ + } \ + } while (0); #else # define JS_LOG(module, log_level, ...) +# define JS_LOG_FMT(module, log_level, fmt, ...) #endif #undef JS_LOGGING diff --git a/js/xpconnect/src/XPCJSContext.cpp b/js/xpconnect/src/XPCJSContext.cpp index 5fa6669c0f98..12a39ed677ae 100644 --- a/js/xpconnect/src/XPCJSContext.cpp +++ b/js/xpconnect/src/XPCJSContext.cpp @@ -52,6 +52,7 @@ #include "js/MemoryMetrics.h" #include "js/Prefs.h" #include "js/WasmFeatures.h" +#include "fmt/format.h" #include "mozilla/dom/BindingUtils.h" #include "mozilla/dom/ContentChild.h" #include "mozilla/dom/Document.h" @@ -1182,13 +1183,20 @@ static void LogPrintVA(JS::OpaqueLogger aLogger, mozilla::LogLevel level, logmod->Printv(level, aFmt, ap); } +static void LogPrintFMT(JS::OpaqueLogger aLogger, mozilla::LogLevel level, + fmt::string_view fmt, fmt::format_args args) { + LogModule* logmod = static_cast(aLogger); + + logmod->PrintvFmt(level, fmt, args); +} + static AtomicLogLevel& GetLevelRef(JS::OpaqueLogger aLogger) { LogModule* logmod = static_cast(aLogger); return logmod->LevelRef(); } static JS::LoggingInterface loggingInterface = {GetLoggerByName, LogPrintVA, - GetLevelRef}; + LogPrintFMT, GetLevelRef}; nsresult XPCJSContext::Initialize() { if (StaticPrefs::javascript_options_external_thread_pool_DoNotUseDirectly()) {