Bug 1172141 - Add a maxLogLevelPref option to the ConsoleAPI constructor to easily control log levels with a preference. r=bgrins
authorMatthew Noorenberghe <mozilla@noorenberghe.ca>
Mon, 08 Jun 2015 00:46:18 -0700
changeset 248056 7584dcefd15c703b85d1a09167f4433b72aaa5d0
parent 248055 dd8df14614dfcb31182f8ea860d27ee3f14453a5
child 248057 84d422afe66ddeb2206a77d0748c17ba50dd77a0
push id60888
push userkwierso@gmail.com
push dateThu, 11 Jun 2015 01:38:38 +0000
treeherdermozilla-inbound@39e638ed06bf [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbgrins
bugs1172141
milestone41.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1172141 - Add a maxLogLevelPref option to the ConsoleAPI constructor to easily control log levels with a preference. r=bgrins
browser/devtools/webconsole/test/browser_console_consolejsm_output.js
browser/devtools/webconsole/test/head.js
toolkit/devtools/Console.jsm
--- a/browser/devtools/webconsole/test/browser_console_consolejsm_output.js
+++ b/browser/devtools/webconsole/test/browser_console_consolejsm_output.js
@@ -2,16 +2,25 @@
  * Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
 // Test that Console.jsm outputs messages to the Browser Console, bug 851231.
 
 "use strict";
 
+function onNewMessage(aEvent, aNewMessages) {
+  for (let msg of aNewMessages) {
+    // Messages that shouldn't be output contain the substring FAIL_TEST
+    if (msg.node.textContent.includes("FAIL_TEST")) {
+      ok(false, "Message shouldn't have been output: " + msg.node.textContent);
+    }
+  }
+};
+
 add_task(function*() {
   let storage = Cc["@mozilla.org/consoleAPI-storage;1"].getService(Ci.nsIConsoleAPIStorage);
   storage.clearEvents();
 
   let {console} = Cu.import("resource://gre/modules/devtools/Console.jsm", {});
   console.log("bug861338-log-cached");
 
   let hud = yield HUDService.toggleBrowserConsole();
@@ -144,25 +153,129 @@ add_task(function* test_prefix() {
 
   let {ConsoleAPI} = Cu.import("resource://gre/modules/devtools/Console.jsm", {});
   let consoleOptions = {
     maxLogLevel: "error",
     prefix: "Log Prefix",
   };
   let console2 = new ConsoleAPI(consoleOptions);
   console2.error("Testing a prefix");
-  console2.log("Below the maxLogLevel");
+  console2.log("FAIL_TEST: Below the maxLogLevel");
 
   let hud = yield HUDService.toggleBrowserConsole();
-
+  hud.ui.on("new-messages", onNewMessage);
   yield waitForMessages({
     webconsole: hud,
     messages: [{
       name: "cached console.error message",
       prefix: "Log Prefix:",
       severity: SEVERITY_ERROR,
       text: "Testing a prefix",
     }],
   });
 
   hud.jsterm.clearOutput(true);
+  hud.ui.off("new-messages", onNewMessage);
+  yield HUDService.toggleBrowserConsole();
+});
+
+add_task(function* test_maxLogLevelPref_missing() {
+  let storage = Cc["@mozilla.org/consoleAPI-storage;1"].getService(Ci.nsIConsoleAPIStorage);
+  storage.clearEvents();
+
+  let {ConsoleAPI} = Cu.import("resource://gre/modules/devtools/Console.jsm", {});
+  let consoleOptions = {
+    maxLogLevel: "error",
+    maxLogLevelPref: "testing.maxLogLevel",
+  };
+  let console = new ConsoleAPI(consoleOptions);
+
+  is(Services.prefs.getPrefType(consoleOptions.maxLogLevelPref),
+     Services.prefs.PREF_INVALID,
+     "Check log level pref is missing");
+
+  // Since the maxLogLevelPref doesn't exist, we should fallback to the passed
+  // maxLogLevel of "error".
+  console.warn("FAIL_TEST: Below the maxLogLevel");
+  console.error("Error should be shown");
+
+  let hud = yield HUDService.toggleBrowserConsole();
+
+  hud.ui.on("new-messages", onNewMessage);
+
+  yield waitForMessages({
+    webconsole: hud,
+    messages: [{
+      name: "defaulting to error level",
+      severity: SEVERITY_ERROR,
+      text: "Error should be shown",
+    }],
+  });
+
+  hud.jsterm.clearOutput(true);
+  hud.ui.off("new-messages", onNewMessage);
   yield HUDService.toggleBrowserConsole();
 });
+
+add_task(function* test_maxLogLevelPref() {
+  let storage = Cc["@mozilla.org/consoleAPI-storage;1"].getService(Ci.nsIConsoleAPIStorage);
+  storage.clearEvents();
+
+  let {ConsoleAPI} = Cu.import("resource://gre/modules/devtools/Console.jsm", {});
+  let consoleOptions = {
+    maxLogLevel: "error",
+    maxLogLevelPref: "testing.maxLogLevel",
+  };
+
+  info("Setting the pref to warn");
+  Services.prefs.setCharPref(consoleOptions.maxLogLevelPref, "Warn");
+
+  let console = new ConsoleAPI(consoleOptions);
+
+  is(console.maxLogLevel, "warn", "Check pref was read at initialization");
+
+  console.info("FAIL_TEST: info is below the maxLogLevel");
+  console.error("Error should be shown");
+  console.warn("Warn should be shown due to the initial pref value");
+
+  info("Setting the pref to info");
+  Services.prefs.setCharPref(consoleOptions.maxLogLevelPref, "INFO");
+  is(console.maxLogLevel, "info", "Check pref was lowercased");
+
+  console.info("info should be shown due to the pref change being observed");
+
+  info("Clearing the pref");
+  Services.prefs.clearUserPref(consoleOptions.maxLogLevelPref);
+
+  console.warn("FAIL_TEST: Shouldn't be shown due to defaulting to error");
+  console.error("Should be shown due to defaulting to error");
+
+  let hud = yield HUDService.toggleBrowserConsole();
+  hud.ui.on("new-messages", onNewMessage);
+
+  yield waitForMessages({
+    webconsole: hud,
+    messages: [{
+      name: "error > warn",
+      severity: SEVERITY_ERROR,
+      text: "Error should be shown",
+    },
+    {
+      name: "warn is the inital pref value",
+      severity: SEVERITY_WARNING,
+      text: "Warn should be shown due to the initial pref value",
+    },
+    {
+      name: "pref changed to info",
+      severity: SEVERITY_INFO,
+      text: "info should be shown due to the pref change being observed",
+    },
+    {
+      name: "default to intial maxLogLevel if pref is removed",
+      severity: SEVERITY_ERROR,
+      text: "Should be shown due to defaulting to error",
+    }],
+  });
+
+  hud.jsterm.clearOutput(true);
+  hud.ui.off("new-messages", onNewMessage);
+  yield HUDService.toggleBrowserConsole();
+});
--- a/browser/devtools/webconsole/test/head.js
+++ b/browser/devtools/webconsole/test/head.js
@@ -902,16 +902,17 @@ function openDebugger(aOptions = {})
  *            - type: match messages that are instances of the given object. For
  *            example, you can point to Messages.NavigationMarker to match any
  *            such message.
  *            - objects: boolean, set to |true| if you expect inspectable
  *            objects in the message.
  *            - source: object of the shape { url, line }. This is used to
  *            match the source URL and line number of the error message or
  *            console API call.
+ *            - prefix: prefix text to check for in the prefix element.
  *            - stacktrace: array of objects of the form { file, fn, line } that
  *            can match frames in the stacktrace associated with the message.
  *            - groupDepth: number used to check the depth of the message in
  *            a group.
  *            - url: URL to match for network requests.
  * @return object
  *         A promise object is returned once the messages you want are found.
  *         The promise is resolved with the array of rule objects you give in
--- a/toolkit/devtools/Console.jsm
+++ b/toolkit/devtools/Console.jsm
@@ -576,43 +576,71 @@ function sendConsoleAPIMessage(aConsole,
  *        - prefix {string} : An optional prefix string to be printed before
  *                            the actual logged message
  *        - maxLogLevel {string} : String identifier (See LOG_LEVELS for
  *                            possible values) that allows to filter which
  *                            messages are logged based on their log level.
  *                            If falsy value, all messages will be logged.
  *                            If wrong value that doesn't match any key of
  *                            LOG_LEVELS, no message will be logged
+ *        - maxLogLevelPref {string} : String pref name which contains the
+ *                            level to use for maxLogLevel. If the pref doesn't
+ *                            exist or gets removed, the maxLogLevel will default
+ *                            to the value passed to this constructor (or "all"
+ *                            if it wasn't specified).
  *        - dump {function} : An optional function to intercept all strings
  *                            written to stdout
  *        - innerID {string}: An ID representing the source of the message.
  *                            Normally the inner ID of a DOM window.
  *        - consoleID {string} : String identified for the console, this will
  *                            be passed through the console notifications
  * @return {object}
  *        A console API instance object
  */
 function ConsoleAPI(aConsoleOptions = {}) {
   // Normalize console options to set default values
   // in order to avoid runtime checks on each console method call.
   this.dump = aConsoleOptions.dump || dump;
   this.prefix = aConsoleOptions.prefix || "";
-  this.maxLogLevel = aConsoleOptions.maxLogLevel || "all";
+  this.maxLogLevel = aConsoleOptions.maxLogLevel;
   this.innerID = aConsoleOptions.innerID || null;
   this.consoleID = aConsoleOptions.consoleID || "";
 
+  // Setup maxLogLevelPref watching
+  let updateMaxLogLevel = () => {
+    if (Services.prefs.getPrefType(aConsoleOptions.maxLogLevelPref) == Services.prefs.PREF_STRING) {
+      this._maxLogLevel = Services.prefs.getCharPref(aConsoleOptions.maxLogLevelPref).toLowerCase();
+    } else {
+      this._maxLogLevel = this._maxExplicitLogLevel;
+    }
+  };
+
+  if (aConsoleOptions.maxLogLevelPref) {
+    updateMaxLogLevel();
+    Services.prefs.addObserver(aConsoleOptions.maxLogLevelPref, updateMaxLogLevel, false);
+  }
+
   // Bind all the functions to this object.
   for (let prop in this) {
     if (typeof(this[prop]) === "function") {
       this[prop] = this[prop].bind(this);
     }
   }
 }
 
 ConsoleAPI.prototype = {
+  /**
+   * The last log level that was specified via the constructor or setter. This
+   * is used as a fallback if the pref doesn't exist or is removed.
+   */
+  _maxExplicitLogLevel: null,
+  /**
+   * The current log level via all methods of setting (pref or via the API).
+   */
+  _maxLogLevel: null,
   debug: createMultiLineDumper("debug"),
   log: createDumper("log"),
   info: createDumper("info"),
   warn: createDumper("warn"),
   error: createMultiLineDumper("error"),
   exception: createMultiLineDumper("error"),
 
   trace: function Console_trace() {
@@ -650,12 +678,20 @@ ConsoleAPI.prototype = {
     }
     let args = Array.prototype.slice.call(arguments, 0);
     let frame = getStack(Components.stack.caller, 1)[0];
     let timer = stopTimer(args[0]);
     sendConsoleAPIMessage(this, "timeEnd", frame, args, { timer: timer });
     dumpMessage(this, "timeEnd",
                 "'" + timer.name + "' " + timer.duration + "ms");
   },
+
+  get maxLogLevel() {
+    return this._maxLogLevel || "all";
+  },
+
+  set maxLogLevel(aValue) {
+    this._maxLogLevel = this._maxExplicitLogLevel = aValue;
+  },
 };
 
 this.console = new ConsoleAPI();
 this.ConsoleAPI = ConsoleAPI;