commit 69f55982c0aa8f82864fd0a7435204232b802fc8
parent ff8afcd8c4b4fea7f1affb9ebbe38cab23caf8cb
Author: Steve Fink <sfink@mozilla.com>
Date: Wed, 10 Dec 2025 22:26:32 +0000
Bug 2005302 - Add mozLog("...") to dynamically set $MOZ_LOG logging levels for JS shell r=mgaudet
Differential Revision: https://phabricator.services.mozilla.com/D275852
Diffstat:
1 file changed, 50 insertions(+), 12 deletions(-)
diff --git a/js/src/shell/js.cpp b/js/src/shell/js.cpp
@@ -405,25 +405,22 @@ static void ToLower(const char* src, char* dest, size_t len) {
}
}
-// Run this after initialiation!
-void ParseLoggerOptions() {
- char* mixedCaseOpts = getenv("MOZ_LOG");
- if (!mixedCaseOpts) {
- return;
- }
-
+// This should be run once after initialization, and may be rerun (via the
+// mozLog() command) again later.
+static void ParseLoggerOptions(mozilla::Range<const char> mixedCaseOpts) {
// Copy into a new buffer and lower case to do case insensitive matching.
//
// Done this way rather than just using strcasestr because Windows doesn't
// have strcasestr as part of its base C library.
- size_t len = strlen(mixedCaseOpts);
+ size_t len = mixedCaseOpts.length();
mozilla::UniqueFreePtr<char[]> logOpts(
static_cast<char*>(calloc(len + 1, 1)));
if (!logOpts) {
return;
}
- ToLower(mixedCaseOpts, logOpts.get(), len);
+ ToLower(mixedCaseOpts.begin().get(), logOpts.get(), len);
+ logOpts.get()[len] = '\0';
// This is a really permissive parser, but will suffice!
for (auto& logger : logModules) {
@@ -433,11 +430,13 @@ void ParseLoggerOptions() {
mozilla::UniqueFreePtr<char[]> lowerName(
static_cast<char*>(calloc(len + 1, 1)));
ToLower(logger->name, lowerName.get(), len);
+ lowerName.get()[len] = '\0';
+ int logLevel = 0;
if (char* needle = strstr(logOpts.get(), lowerName.get())) {
// If the string to enable a logger is present, but no level is provided
// then default to Debug level.
- int logLevel = static_cast<int>(mozilla::LogLevel::Debug);
+ logLevel = static_cast<int>(mozilla::LogLevel::Debug);
if (char* colon = strchr(needle, ':')) {
// Parse character after colon as log level.
@@ -448,12 +447,41 @@ void ParseLoggerOptions() {
fprintf(stderr, "[JS_LOG] Enabling Logger %s at level %d\n",
logger->name, logLevel);
- logger->level = mozilla::ToLogLevel(logLevel);
+ } else {
+ if (logger->level != mozilla::ToLogLevel(logLevel)) {
+ fprintf(stderr, "[JS_LOG] Resetting Logger %s to level %d\n",
+ logger->name, logLevel);
+ }
}
+
+ logger->level = mozilla::ToLogLevel(logLevel);
}
}
}
+static bool SetMozLog(JSContext* cx, unsigned argc, Value* vp) {
+ CallArgs args = CallArgsFromVp(argc, vp);
+
+ Rooted<JSString*> spec(cx, ToString(cx, args.get(0)));
+ if (!spec) {
+ return false;
+ }
+
+ if (!spec->hasLatin1Chars()) {
+ JS_ReportErrorASCII(cx, "invalid MOZ_LOG setting");
+ return false;
+ }
+
+ AutoStableStringChars stable(cx);
+ if (!stable.init(cx, spec)) {
+ return false;
+ }
+
+ mozilla::Range<const Latin1Char> r = stable.latin1Range();
+ ParseLoggerOptions({(const char*)r.begin().get(), r.length()});
+ return true;
+}
+
/*
* Limit the timeout to 30 minutes to prevent an overflow on platfoms
* that represent the time internally in microseconds using 32-bit int.
@@ -10878,6 +10906,13 @@ TestAssertRecoveredOnBailout,
"decompressLZ4(bytes)",
" Return a decompressed copy of bytes using LZ4."),
+ JS_FN_HELP("mozLog", SetMozLog, 0, 0,
+"mozLog(\"logLevels\")",
+" Modify log levels as if MOZ_LOG had been set to this at startup.\n"
+" `logLevels` is a comma-separated list of log modules, each\n"
+" with an optional \":<level>\" (defaults to 5 aka Debug).\n"
+" example: mozLog('gc,wasm:4')"),
+
JS_FS_HELP_END
};
// clang-format on
@@ -12707,7 +12742,10 @@ int main(int argc, char** argv) {
if (!JS::SetLoggingInterface(shellLoggingInterface)) {
return 1;
}
- ParseLoggerOptions();
+ char* logopts = getenv("MOZ_LOG");
+ if (logopts) {
+ ParseLoggerOptions(mozilla::Range(logopts, strlen(logopts)));
+ }
// Start the engine.
if (const char* message = JS_InitWithFailureDiagnostic()) {