diff --git a/toolkit/modules/Log.jsm b/toolkit/modules/Log.jsm index 2223cbcc548e..14f9afb13474 100644 --- a/toolkit/modules/Log.jsm +++ b/toolkit/modules/Log.jsm @@ -265,12 +265,33 @@ function Logger(name, repository) { this._repository = repository; } Logger.prototype = { + _levelPrefName: null, + _levelPrefValue: null, + get name() { return this._name; }, _level: null, get level() { + if (this._levelPrefName) { + // We've been asked to use a preference to configure the logs. If the + // pref has a value we use it, otherwise we continue to use the parent. + const lpv = this._levelPrefValue; + if (lpv) { + const levelValue = Log.Level[lpv]; + if (levelValue) { + // stash it in _level just in case a future value of the pref is + // invalid, in which case we end up continuing to use this value. + this._level = levelValue; + return levelValue; + } + } else { + // in case the pref has transitioned from a value to no value, we reset + // this._level and fall through to using the parent. + this._level = null; + } + } if (this._level != null) return this._level; if (this.parent) @@ -279,6 +300,15 @@ Logger.prototype = { return Log.Level.All; }, set level(level) { + if (this._levelPrefName) { + // I guess we could honor this by nuking this._levelPrefValue, but it + // almost certainly implies confusion, so we'll warn and ignore. + dumpError(`Log warning: The log '${this.name}' is configured to use ` + + `the preference '${this._levelPrefName}' - you must adjust ` + + `the level by setting this preference, not by using the ` + + `level setter`); + return; + } this._level = level; }, @@ -302,6 +332,21 @@ Logger.prototype = { this.updateAppenders(); }, + manageLevelFromPref(prefName) { + if (prefName == this._levelPrefName) { + // We've already configured this log with an observer for that pref. + return; + } + if (this._levelPrefName) { + dumpError(`The log '${this.name}' is already configured with the ` + + `preference '${this._levelPrefName}' - ignoring request to ` + + `also use the preference '${prefName}'`); + return; + } + this._levelPrefName = prefName; + XPCOMUtils.defineLazyPreferenceGetter(this, "_levelPrefValue", prefName); + }, + updateAppenders: function updateAppenders() { if (this._parent) { let notOwnAppenders = this._parent.appenders.filter(function(appender) { diff --git a/toolkit/modules/tests/xpcshell/test_Log.js b/toolkit/modules/tests/xpcshell/test_Log.js index 12ede292776f..d3d58bbc5552 100644 --- a/toolkit/modules/tests/xpcshell/test_Log.js +++ b/toolkit/modules/tests/xpcshell/test_Log.js @@ -588,3 +588,34 @@ add_task(function* format_errors() { do_check_true(str.includes("format_errors")); } }); + +/* + * Check that automatic support for setting the log level via preferences + * works. + */ +add_test(function test_prefs() { + let log = Log.repository.getLogger("error.logger"); + log.level = Log.Level.Debug; + Services.prefs.setStringPref("logger.test", "Error"); + log.manageLevelFromPref("logger.test"); + // check initial pref value is set up. + equal(log.level, Log.Level.Error); + Services.prefs.setStringPref("logger.test", "Error"); + // check changing the pref causes the level to change. + Services.prefs.setStringPref("logger.test", "Trace"); + equal(log.level, Log.Level.Trace); + // invalid values cause nothing to happen. + Services.prefs.setStringPref("logger.test", "invalid-level-value"); + equal(log.level, Log.Level.Trace); + Services.prefs.setIntPref("logger.test", 123); + equal(log.level, Log.Level.Trace); + // setting a "sub preference" shouldn't impact it. + Services.prefs.setStringPref("logger.test.foo", "Debug"); + equal(log.level, Log.Level.Trace); + // clearing the level param should cause it to use the parent level. + Log.repository.getLogger("error").level = Log.Level.All; + Services.prefs.setStringPref("logger.test", ""); + equal(log.level, Log.Level.All); + + run_next_test(); +});