Bug 861338 - [browserconsole] Cache Console.jsm API calls with ConsoleAPIStorage.jsm; r=jwalker
authorMihai Sucan <mihai.sucan@gmail.com>
Fri, 07 Jun 2013 20:13:48 +0300
changeset 134673 f4ec1953f7e5ce16e43b545de724bbc51b08b43c
parent 134672 59d6cff1a48e42de1df5e632455dfdb7fb2f793e
child 134674 acc83523042859fe4389993f95aab1f5efc68946
push id29326
push userryanvm@gmail.com
push dateTue, 11 Jun 2013 19:01:46 +0000
treeherdermozilla-inbound@5fd0dc3b821b [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjwalker
bugs861338
milestone24.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 861338 - [browserconsole] Cache Console.jsm API calls with ConsoleAPIStorage.jsm; r=jwalker
browser/devtools/webconsole/test/browser_console_consolejsm_output.js
browser/devtools/webconsole/test/browser_webconsole_bug_642108_pruneTest.js
dom/base/ConsoleAPIStorage.jsm
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,25 +2,42 @@
  * 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.
 
 function test()
 {
+  let storage = Cu.import("resource://gre/modules/ConsoleAPIStorage.jsm", {}).ConsoleAPIStorage;
+  storage.clearEvents();
+
+  let console = Cu.import("resource://gre/modules/devtools/Console.jsm", {}).console;
+  console.log("bug861338-log-cached");
+
   HUDConsoleUI.toggleBrowserConsole().then(consoleOpened);
   let hud = null;
 
   function consoleOpened(aHud)
   {
     hud = aHud;
-    hud.jsterm.clearOutput(true);
+    waitForMessages({
+      webconsole: hud,
+      messages: [{
+        name: "cached console.log message",
+        text: "bug861338-log-cached",
+        category: CATEGORY_WEBDEV,
+        severity: SEVERITY_LOG,
+      }],
+    }).then(onCachedMessage);
+  }
 
-    let console = Cu.import("resource://gre/modules/devtools/Console.jsm", {}).console;
+  function onCachedMessage()
+  {
+    hud.jsterm.clearOutput(true);
 
     console.time("foobarTimer");
     let foobar = { bug851231prop: "bug851231value" };
 
     console.log("bug851231-log");
     console.info("bug851231-info");
     console.warn("bug851231-warn");
     console.error("bug851231-error", foobar);
@@ -64,17 +81,17 @@ function test()
           text: "bug851231-debug",
           category: CATEGORY_WEBDEV,
           severity: SEVERITY_LOG,
         },
         {
           name: "console.trace output",
           consoleTrace: {
             file: "browser_console_consolejsm_output.js",
-            fn: "consoleOpened",
+            fn: "onCachedMessage",
           },
         },
         {
           name: "console.dir output",
           consoleDir: "[object XULDocument]",
         },
         {
           name: "console.time output",
--- a/browser/devtools/webconsole/test/browser_webconsole_bug_642108_pruneTest.js
+++ b/browser/devtools/webconsole/test/browser_webconsole_bug_642108_pruneTest.js
@@ -67,19 +67,16 @@ function testCSSPruning(hudRef) {
   };
 
   waitForSuccess({
     name: "repeated nodes in cssNodes",
     validatorFn: function()
     {
       let msg = hudRef.outputNode.querySelector(".webconsole-msg-cssparser " +
                                                 ".webconsole-msg-repeat");
-      if (msg) {
-        console.debug(msg, msg.getAttribute("value"));
-      }
       return msg && msg.getAttribute("value") == 5;
     },
     successFn: function()
     {
       populateConsole(hudRef);
       waitForSuccess(waitForNoRepeatedNodes);
     },
     failureFn: finishTest,
--- a/dom/base/ConsoleAPIStorage.jsm
+++ b/dom/base/ConsoleAPIStorage.jsm
@@ -1,24 +1,26 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
+"use strict";
+
 let Cu = Components.utils;
 let Ci = Components.interfaces;
 let Cc = Components.classes;
 
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource://gre/modules/Services.jsm");
 
 const STORAGE_MAX_EVENTS = 200;
 
 this.EXPORTED_SYMBOLS = ["ConsoleAPIStorage"];
 
-var _consoleStorage = {};
+var _consoleStorage = new Map();
 
 /**
  * The ConsoleAPIStorage is meant to cache window.console API calls for later
  * reuse by other components when needed. For example, the Web Console code can
  * display the cached messages when it opens for the active tab.
  *
  * ConsoleAPI messages are stored as they come from the ConsoleAPI code, with
  * all their properties. They are kept around until the inner window object that
@@ -73,74 +75,69 @@ this.ConsoleAPIStorage = {
    * @returns array
    *          The array of cached events for the given window. If no |aId| is
    *          given this function returns all of the cached events, from any
    *          window.
    */
   getEvents: function CS_getEvents(aId)
   {
     if (aId != null) {
-      return (_consoleStorage[aId] || []).slice(0);
+      return (_consoleStorage.get(aId) || []).slice(0);
     }
 
-    let ids = [];
+    let result = [];
 
-    for each (let events in _consoleStorage) {
-      ids.push(events);
+    for (let [id, events] of _consoleStorage) {
+      result.push.apply(result, events);
     }
 
-    let result = [].concat.apply([], ids);
-
     return result.sort(function(a, b) {
       return a.timeStamp - b.timeStamp;
     });
   },
 
   /**
    * Record an event associated with the given window ID.
    *
-   * @param string aWindowID
-   *        The ID of the inner window for which the event occurred.
+   * @param string aId
+   *        The ID of the inner window for which the event occurred or "jsm" for
+   *        messages logged from JavaScript modules..
    * @param object aEvent
    *        A JavaScript object you want to store.
    */
-  recordEvent: function CS_recordEvent(aWindowID, aEvent)
+  recordEvent: function CS_recordEvent(aId, aEvent)
   {
-    let ID = parseInt(aWindowID);
-    if (isNaN(ID)) {
-      throw new Error("Invalid window ID argument");
+    if (!_consoleStorage.has(aId)) {
+      _consoleStorage.set(aId, []);
     }
 
-    if (!_consoleStorage[ID]) {
-      _consoleStorage[ID] = [];
-    }
-    let storage = _consoleStorage[ID];
+    let storage = _consoleStorage.get(aId);
     storage.push(aEvent);
 
     // truncate
     if (storage.length > STORAGE_MAX_EVENTS) {
       storage.shift();
     }
 
-    Services.obs.notifyObservers(aEvent, "console-storage-cache-event", ID);
+    Services.obs.notifyObservers(aEvent, "console-storage-cache-event", aId);
   },
 
   /**
    * Clear storage data for the given window.
    *
    * @param string [aId]
    *        Optional, the inner window ID for which you want to clear the
    *        messages. If this is not specified all of the cached messages are
    *        cleared, from all window objects.
    */
   clearEvents: function CS_clearEvents(aId)
   {
     if (aId != null) {
-      delete _consoleStorage[aId];
+      _consoleStorage.delete(aId);
     }
     else {
-      _consoleStorage = {};
+      _consoleStorage.clear();
       Services.obs.notifyObservers(null, "console-storage-reset", null);
     }
   },
 };
 
 ConsoleAPIStorage.init();
--- a/toolkit/devtools/Console.jsm
+++ b/toolkit/devtools/Console.jsm
@@ -17,17 +17,20 @@
  * - The Firebug console is a rich display compared with dump(), so there will
  *   be many things that we can't replicate
  * - The primary use of this API is debugging and error logging so the perfect
  *   implementation isn't always required (or even well defined)
  */
 
 this.EXPORTED_SYMBOLS = [ "console" ];
 
-Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
+const Cu = Components.utils;
+
+Cu.import("resource://gre/modules/XPCOMUtils.jsm");
+Cu.import("resource://gre/modules/ConsoleAPIStorage.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "Services",
                                   "resource://gre/modules/Services.jsm");
 
 let gTimerRegistry = new Map();
 
 /**
  * String utility to ensure that strings are a specified length. Strings
@@ -448,17 +451,18 @@ function createMultiLineDumper(aLevel) {
  *        - timer: for time() and timeEnd(). Holds the timer information.
  *        - groupName: for group(), groupCollapsed() and groupEnd().
  *        - stacktrace: for trace(). Holds the array of stack frames as given by
  *        getStack().
  */
 function sendConsoleAPIMessage(aLevel, aFrame, aArgs, aOptions = {})
 {
   let consoleEvent = {
-    ID: aFrame.filename,
+    ID: "jsm",
+    innerID: aFrame.filename,
     level: aLevel,
     filename: aFrame.filename,
     lineNumber: aFrame.lineNumber,
     functionName: aFrame.functionName,
     timeStamp: Date.now(),
     arguments: aArgs,
   };
 
@@ -482,16 +486,17 @@ function sendConsoleAPIMessage(aLevel, a
         Cu.reportError(ex);
         Cu.reportError(ex.stack);
         return;
       }
       break;
   }
 
   Services.obs.notifyObservers(consoleEvent, "console-api-log-event", null);
+  ConsoleAPIStorage.recordEvent("jsm", consoleEvent);
 }
 
 /**
  * This creates a console object that somewhat replicates Firebug's console
  * object.
  */
 this.console = {
   debug: createMultiLineDumper("debug"),