Bug 787985 - Console API messages are not consistent; r=past
authorMihai Sucan <mihai.sucan@gmail.com>
Tue, 15 Jan 2013 16:02:25 +0200
changeset 119042 1a39357d5197345ffcfa0c7c35452855920bb2ad
parent 119041 0b8ed05852d24afd8c5ce5c92dd6e7bcede32c66
child 119043 50ea8eac36c25bfc0afb74f7357348f73a9c38a1
push id21433
push useremorley@mozilla.com
push dateWed, 16 Jan 2013 20:27:50 +0000
treeherdermozilla-inbound@c4b6301bee26 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerspast
bugs787985
milestone21.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 787985 - Console API messages are not consistent; r=past
browser/devtools/webconsole/webconsole.js
dom/base/ConsoleAPI.js
dom/tests/browser/browser_ConsoleAPITests.js
toolkit/devtools/debugger/dbg-transport.js
toolkit/devtools/webconsole/dbg-webconsole-actors.js
toolkit/devtools/webconsole/test/test_consoleapi.html
--- a/browser/devtools/webconsole/webconsole.js
+++ b/browser/devtools/webconsole/webconsole.js
@@ -988,138 +988,149 @@ WebConsoleFrame.prototype = {
    *        The message received from the server.
    * @return nsIDOMElement|undefined
    *         The message element to display in the Web Console output.
    */
   logConsoleAPIMessage: function WCF_logConsoleAPIMessage(aMessage)
   {
     let body = null;
     let clipboardText = null;
-    let sourceURL = null;
-    let sourceLine = 0;
+    let sourceURL = aMessage.filename;
+    let sourceLine = aMessage.lineNumber;
     let level = aMessage.level;
     let args = aMessage.arguments;
     let objectActors = [];
 
+    // Gather the actor IDs.
+    args.forEach(function(aValue) {
+      if (aValue && typeof aValue == "object" && aValue.actor) {
+        objectActors.push(aValue.actor);
+        let displayStringIsLong = typeof aValue.displayString == "object" &&
+                                  aValue.displayString.type == "longString";
+        if (displayStringIsLong) {
+          objectActors.push(aValue.displayString.actor);
+        }
+      }
+    }, this);
+
     switch (level) {
       case "log":
       case "info":
       case "warn":
       case "error":
       case "debug":
       case "dir":
       case "groupEnd": {
         body = { arguments: args };
         let clipboardArray = [];
         args.forEach(function(aValue) {
           clipboardArray.push(WebConsoleUtils.objectActorGripToString(aValue));
           if (aValue && typeof aValue == "object" && aValue.actor) {
-            objectActors.push(aValue.actor);
             let displayStringIsLong = typeof aValue.displayString == "object" &&
                                       aValue.displayString.type == "longString";
             if (aValue.type == "longString" || displayStringIsLong) {
               clipboardArray.push(l10n.getStr("longStringEllipsis"));
             }
-            if (displayStringIsLong) {
-              objectActors.push(aValue.displayString.actor);
-            }
           }
         }, this);
         clipboardText = clipboardArray.join(" ");
-        sourceURL = aMessage.filename;
-        sourceLine = aMessage.lineNumber;
 
         if (level == "dir") {
           body.objectProperties = aMessage.objectProperties;
         }
-        else if (level == "groupEnd") {
-          objectActors.forEach(this._releaseObject, this);
-
-          if (this.groupDepth > 0) {
-            this.groupDepth--;
-          }
-          return; // no need to continue
-        }
-
         break;
       }
 
       case "trace": {
-        let filename = WebConsoleUtils.abbreviateSourceURL(args[0].filename);
-        let functionName = args[0].functionName ||
+        let filename = WebConsoleUtils.abbreviateSourceURL(aMessage.filename);
+        let functionName = aMessage.functionName ||
                            l10n.getStr("stacktrace.anonymousFunction");
-        let lineNumber = args[0].lineNumber;
 
         body = l10n.getFormatStr("stacktrace.outputMessage",
-                                 [filename, functionName, lineNumber]);
-
-        sourceURL = args[0].filename;
-        sourceLine = args[0].lineNumber;
+                                 [filename, functionName, sourceLine]);
 
         clipboardText = "";
 
-        args.forEach(function(aFrame) {
+        aMessage.stacktrace.forEach(function(aFrame) {
           clipboardText += aFrame.filename + " :: " +
                            aFrame.functionName + " :: " +
                            aFrame.lineNumber + "\n";
         });
 
         clipboardText = clipboardText.trimRight();
         break;
       }
 
       case "group":
       case "groupCollapsed":
-        clipboardText = body = args;
-        sourceURL = aMessage.filename;
-        sourceLine = aMessage.lineNumber;
+        clipboardText = body = aMessage.groupName;
         this.groupDepth++;
         break;
 
-      case "time":
-        if (!args) {
+      case "time": {
+        let timer = aMessage.timer;
+        if (!timer) {
           return;
         }
-        if (args.error) {
-          Cu.reportError(l10n.getStr(args.error));
+        if (timer.error) {
+          Cu.reportError(l10n.getStr(timer.error));
           return;
         }
-        body = l10n.getFormatStr("timerStarted", [args.name]);
+        body = l10n.getFormatStr("timerStarted", [timer.name]);
         clipboardText = body;
-        sourceURL = aMessage.filename;
-        sourceLine = aMessage.lineNumber;
         break;
-
-      case "timeEnd":
-        if (!args) {
+      }
+
+      case "timeEnd": {
+        let timer = aMessage.timer;
+        if (!timer) {
           return;
         }
-        body = l10n.getFormatStr("timeEnd", [args.name, args.duration]);
+        body = l10n.getFormatStr("timeEnd", [timer.name, timer.duration]);
         clipboardText = body;
-        sourceURL = aMessage.filename;
-        sourceLine = aMessage.lineNumber;
         break;
+      }
 
       default:
         Cu.reportError("Unknown Console API log level: " + level);
         return;
     }
 
+    // Release object actors for arguments coming from console API methods that
+    // we ignore their arguments.
+    switch (level) {
+      case "group":
+      case "groupCollapsed":
+      case "groupEnd":
+      case "trace":
+      case "time":
+      case "timeEnd":
+        objectActors.forEach(this._releaseObject, this);
+        objectActors = [];
+    }
+
+    if (level == "groupEnd") {
+      if (this.groupDepth > 0) {
+        this.groupDepth--;
+      }
+      return; // no need to continue
+    }
+
     let node = this.createMessageNode(CATEGORY_WEBDEV, LEVELS[level], body,
                                       sourceURL, sourceLine, clipboardText,
                                       level, aMessage.timeStamp);
 
     if (objectActors.length) {
       node._objectActors = objectActors;
     }
 
     // Make the node bring up the property panel, to allow the user to inspect
     // the stack trace.
     if (level == "trace") {
-      node._stacktrace = args;
+      node._stacktrace = aMessage.stacktrace;
 
       this.makeOutputMessageLink(node, function _traceNodeClickCallback() {
         if (node._panelOpen) {
           return;
         }
 
         let options = {
           anchor: node,
--- a/dom/base/ConsoleAPI.js
+++ b/dom/base/ConsoleAPI.js
@@ -250,90 +250,88 @@ ConsoleAPI.prototype = {
    * @private
    * @param array aCall
    *        Array that holds information about the queued call.
    */
   _processQueuedCall: function CA__processQueuedItem(aCall)
   {
     let [method, args, meta] = aCall;
 
-    let notifyMeta = {
-      isPrivate: meta.isPrivate,
+    let frame = meta.stack[0];
+    let consoleEvent = {
+      ID: this._outerID,
+      innerID: this._innerID,
+      level: method,
+      filename: frame.filename,
+      lineNumber: frame.lineNumber,
+      functionName: frame.functionName,
       timeStamp: meta.timeStamp,
-      frame: meta.stack[0],
+      arguments: args,
     };
 
-    let notifyArguments = null;
-
     switch (method) {
       case "log":
       case "info":
       case "warn":
       case "error":
       case "debug":
-        notifyArguments = this.processArguments(args);
+        consoleEvent.arguments = this.processArguments(args);
         break;
       case "trace":
-        notifyArguments = meta.stack;
+        consoleEvent.stacktrace = meta.stack;
         break;
       case "group":
       case "groupCollapsed":
-        notifyArguments = this.beginGroup(args);
+      case "groupEnd":
+        try {
+          consoleEvent.groupName = Array.prototype.join.call(args, " ");
+        }
+        catch (ex) {
+          Cu.reportError(ex);
+          Cu.reportError(ex.stack);
+          return;
+        }
         break;
-      case "groupEnd":
       case "dir":
-        notifyArguments = args;
         break;
       case "time":
-        notifyArguments = this.startTimer(args[0], meta.timeStamp);
+        consoleEvent.timer = this.startTimer(args[0], meta.timeStamp);
         break;
       case "timeEnd":
-        notifyArguments = this.stopTimer(args[0], meta.timeStamp);
+        consoleEvent.timer = this.stopTimer(args[0], meta.timeStamp);
         break;
       default:
         // unknown console API method!
         return;
     }
 
-    this.notifyObservers(method, notifyArguments, notifyMeta);
+    this.notifyObservers(method, consoleEvent, meta.isPrivate);
   },
 
   /**
    * Notify all observers of any console API call.
    *
    * @param string aLevel
    *        The message level.
-   * @param mixed aArguments
-   *        The arguments given to the console API call.
-   * @param object aMeta
-   *        Object that holds metadata about the console API call:
-   *        - isPrivate - Whether the window is in private browsing mode.
-   *        - frame - the youngest content frame in the call stack.
-   *        - timeStamp - when the console API call occurred.
+   * @param object aConsoleEvent
+   *        The console event object to send to observers for the given console
+   *        API call.
+   * @param boolean aPrivate
+   *        Tells whether the window is in private browsing mode.
    */
-  notifyObservers: function CA_notifyObservers(aLevel, aArguments, aMeta) {
-    let consoleEvent = {
-      ID: this._outerID,
-      innerID: this._innerID,
-      level: aLevel,
-      filename: aMeta.frame.filename,
-      lineNumber: aMeta.frame.lineNumber,
-      functionName: aMeta.frame.functionName,
-      arguments: aArguments,
-      timeStamp: aMeta.timeStamp,
-    };
-
-    consoleEvent.wrappedJSObject = consoleEvent;
+  notifyObservers: function CA_notifyObservers(aLevel, aConsoleEvent, aPrivate)
+  {
+    aConsoleEvent.wrappedJSObject = aConsoleEvent;
 
     // Store non-private messages for which the inner window was not destroyed.
-    if (!aMeta.isPrivate) {
-      ConsoleAPIStorage.recordEvent(this._innerID, consoleEvent);
+    if (!aPrivate) {
+      ConsoleAPIStorage.recordEvent(this._innerID, aConsoleEvent);
     }
 
-    Services.obs.notifyObservers(consoleEvent, "console-api-log-event",
+    Services.obs.notifyObservers(aConsoleEvent, "console-api-log-event",
                                  this._outerID);
   },
 
   /**
    * Process the console API call arguments in order to perform printf-like
    * string substitution.
    *
    * TODO: object substitution should take into account width and precision
@@ -413,23 +411,16 @@ ConsoleAPI.prototype = {
           break;
         }
       }
     }
 
     return stack;
   },
 
-  /**
-   * Begin a new group for logging output together.
-   **/
-  beginGroup: function CA_beginGroup() {
-    return Array.prototype.join.call(arguments[0], " ");
-  },
-
   /*
    * A registry of started timers. Timer maps are key-value pairs of timer
    * names to timer start times, for all timers defined in the page. Timer
    * names are prepended with the inner window ID in order to avoid conflicts
    * with Object.prototype functions.
    */
   timerRegistry: null,
 
--- a/dom/tests/browser/browser_ConsoleAPITests.js
+++ b/dom/tests/browser/browser_ConsoleAPITests.js
@@ -34,23 +34,24 @@ function test() {
 }
 
 function testConsoleData(aMessageObject) {
   let messageWindow = getWindowByWindowId(aMessageObject.ID);
   is(messageWindow, gWindow, "found correct window by window ID");
 
   is(aMessageObject.level, gLevel, "expected level received");
   ok(aMessageObject.arguments, "we have arguments");
-  is(aMessageObject.arguments.length, gArgs.length, "arguments.length matches");
 
   if (gLevel == "trace") {
-    is(aMessageObject.arguments.toSource(), gArgs.toSource(),
+    is(aMessageObject.arguments.length, 0, "arguments.length matches");
+    is(aMessageObject.stacktrace.toSource(), gArgs.toSource(),
        "stack trace is correct");
   }
   else {
+    is(aMessageObject.arguments.length, gArgs.length, "arguments.length matches");
     gArgs.forEach(function (a, i) {
       is(aMessageObject.arguments[i], a, "correct arg " + i);
     });
   }
 
   gTestDriver.next();
 }
 
@@ -96,23 +97,29 @@ function testConsoleGroup(aMessageObject
      aMessageObject.level == "groupCollapsed" ||
      aMessageObject.level == "groupEnd",
      "expected level received");
 
   is(aMessageObject.functionName, "testGroups", "functionName matches");
   ok(aMessageObject.lineNumber >= 45 && aMessageObject.lineNumber <= 47,
      "lineNumber matches");
   if (aMessageObject.level == "groupCollapsed") {
-    ok(aMessageObject.arguments == "a group", "groupCollapsed arguments matches");
+    is(aMessageObject.groupName, "a group", "groupCollapsed groupName matches");
+    is(aMessageObject.arguments[0], "a", "groupCollapsed arguments[0] matches");
+    is(aMessageObject.arguments[1], "group", "groupCollapsed arguments[0] matches");
   }
   else if (aMessageObject.level == "group") {
-    ok(aMessageObject.arguments == "b group", "group arguments matches");
+    is(aMessageObject.groupName, "b group", "group groupName matches");
+    is(aMessageObject.arguments[0], "b", "group arguments[0] matches");
+    is(aMessageObject.arguments[1], "group", "group arguments[1] matches");
   }
   else if (aMessageObject.level == "groupEnd") {
-    ok(Array.prototype.join.call(aMessageObject.arguments, " ") == "b group", "groupEnd arguments matches");
+    let groupName = Array.prototype.join.call(aMessageObject.arguments, " ");
+    is(groupName,"b group", "groupEnd arguments matches");
+    is(aMessageObject.groupName, "b group", "groupEnd groupName matches");
   }
 
   if (aMessageObject.level == "groupEnd") {
     startTimeTest();
   }
 }
 
 function startTraceTest() {
@@ -247,33 +254,42 @@ function startTimeTest() {
     } catch (ex) {
       // XXX Exceptions in this function currently aren't reported, because of
       // some XPConnect weirdness, so report them manually
       ok(false, "Exception thrown in CO_observe: " + ex);
     }
   };
   gLevel = "time";
   gArgs = [
-    {filename: TEST_URI, lineNumber: 23, functionName: "startTimer"},
+    {filename: TEST_URI, lineNumber: 23, functionName: "startTimer",
+     arguments: ["foo"],
+     timer: { name: "foo" },
+    }
   ];
 
   let button = gWindow.document.getElementById("test-time");
   ok(button, "found #test-time button");
   EventUtils.synthesizeMouseAtCenter(button, {}, gWindow);
 }
 
 function testConsoleTime(aMessageObject) {
   let messageWindow = getWindowByWindowId(aMessageObject.ID);
   is(messageWindow, gWindow, "found correct window by window ID");
 
   is(aMessageObject.level, gLevel, "expected level received");
 
   is(aMessageObject.filename, gArgs[0].filename, "filename matches");
   is(aMessageObject.lineNumber, gArgs[0].lineNumber, "lineNumber matches");
   is(aMessageObject.functionName, gArgs[0].functionName, "functionName matches");
+  is(aMessageObject.timer.name, gArgs[0].timer.name, "timer.name matches");
+  ok(aMessageObject.timer.started, "timer.started exists");
+
+  gArgs[0].arguments.forEach(function (a, i) {
+    is(aMessageObject.arguments[i], a, "correct arg " + i);
+  });
 
   startTimeEndTest();
 }
 
 function startTimeEndTest() {
   // Reset the observer function to cope with the fabricated test data.
   ConsoleObserver.observe = function CO_observe(aSubject, aTopic, aData) {
     try {
@@ -281,17 +297,20 @@ function startTimeEndTest() {
     } catch (ex) {
       // XXX Exceptions in this function currently aren't reported, because of
       // some XPConnect weirdness, so report them manually
       ok(false, "Exception thrown in CO_observe: " + ex);
     }
   };
   gLevel = "timeEnd";
   gArgs = [
-    {filename: TEST_URI, lineNumber: 27, functionName: "stopTimer", arguments: { name: "foo" }},
+    {filename: TEST_URI, lineNumber: 27, functionName: "stopTimer",
+     arguments: ["foo"],
+     timer: { name: "foo" },
+    },
   ];
 
   let button = gWindow.document.getElementById("test-timeEnd");
   ok(button, "found #test-timeEnd button");
   EventUtils.synthesizeMouseAtCenter(button, {}, gWindow);
 }
 
 function testConsoleTimeEnd(aMessageObject) {
@@ -300,19 +319,23 @@ function testConsoleTimeEnd(aMessageObje
 
   is(aMessageObject.level, gLevel, "expected level received");
   ok(aMessageObject.arguments, "we have arguments");
 
   is(aMessageObject.filename, gArgs[0].filename, "filename matches");
   is(aMessageObject.lineNumber, gArgs[0].lineNumber, "lineNumber matches");
   is(aMessageObject.functionName, gArgs[0].functionName, "functionName matches");
   is(aMessageObject.arguments.length, gArgs[0].arguments.length, "arguments.length matches");
-  is(aMessageObject.arguments.name, gArgs[0].arguments.name, "timer name matches");
-  ok(typeof aMessageObject.arguments.duration == "number", "timer duration is a number");
-  ok(aMessageObject.arguments.duration > 0, "timer duration is positive");
+  is(aMessageObject.timer.name, gArgs[0].timer.name, "timer name matches");
+  is(typeof aMessageObject.timer.duration, "number", "timer duration is a number");
+  ok(aMessageObject.timer.duration > 0, "timer duration is positive");
+
+  gArgs[0].arguments.forEach(function (a, i) {
+    is(aMessageObject.arguments[i], a, "correct arg " + i);
+  });
 
   startEmptyTimerTest();
 }
 
 function startEmptyTimerTest() {
   // Reset the observer function to cope with the fabricated test data.
   ConsoleObserver.observe = function CO_observe(aSubject, aTopic, aData) {
     try {
@@ -330,17 +353,18 @@ function startEmptyTimerTest() {
 }
 
 function testEmptyTimer(aMessageObject) {
   let messageWindow = getWindowByWindowId(aMessageObject.ID);
   is(messageWindow, gWindow, "found correct window by window ID");
 
   ok(aMessageObject.level == "time" || aMessageObject.level == "timeEnd",
      "expected level received");
-  ok(!aMessageObject.arguments, "we don't have arguments");
+  is(aMessageObject.arguments.length, 0, "we don't have arguments");
+  ok(!aMessageObject.timer, "we don't have a timer");
 
   is(aMessageObject.functionName, "namelessTimer", "functionName matches");
   ok(aMessageObject.lineNumber == 31 || aMessageObject.lineNumber == 32,
      "lineNumber matches");
   // Test finished
   ConsoleObserver.destroy();
   finish();
 }
--- a/toolkit/devtools/debugger/dbg-transport.js
+++ b/toolkit/devtools/debugger/dbg-transport.js
@@ -118,17 +118,21 @@ DebuggerTransport.prototype = {
 
   onDataAvailable: function DT_onDataAvailable(aRequest, aContext,
                                                 aStream, aOffset, aCount) {
     try {
       this._incoming += NetUtil.readInputStreamToString(aStream,
                                                         aStream.available());
       while (this._processIncoming()) {};
     } catch(e) {
-      dumpn("Unexpected error reading from debugging connection: " + e + " - " + e.stack);
+      let msg = "Unexpected error reading from debugging connection: " + e + " - " + e.stack;
+      if (Cu.reportError) {
+        Cu.reportError(msg);
+      }
+      dump(msg + "\n");
       this.close();
       return;
     }
   },
 
   /**
    * Process incoming packets. Returns true if a packet has been received, either
    * if it was properly parsed or not. Returns false if the incoming stream does
@@ -153,28 +157,36 @@ DebuggerTransport.prototype = {
     this._incoming = this._incoming.substring(sep + 1);
     let packet = this._incoming.substring(0, count);
     this._incoming = this._incoming.substring(count);
 
     try {
       packet = this._converter.ConvertToUnicode(packet);
       var parsed = JSON.parse(packet);
     } catch(e) {
-      dumpn("Error parsing incoming packet: " + packet + " (" + e + " - " + e.stack + ")");
+      let msg = "Error parsing incoming packet: " + packet + " (" + e + " - " + e.stack + ")";
+      if (Cu.reportError) {
+        Cu.reportError(msg);
+      }
+      dump(msg + "\n");
       return true;
     }
 
     try {
       dumpn("Got: " + packet);
       let self = this;
       Services.tm.currentThread.dispatch({run: function() {
         self.hooks.onPacket(parsed);
       }}, 0);
     } catch(e) {
-      dumpn("Error handling incoming packet: " + e + " - " + e.stack);
+      let msg = "Error handling incoming packet: " + e + " - " + e.stack;
+      if (Cu.reportError) {
+        Cu.reportError(msg);
+      }
+      dump(msg + "\n");
       dumpn("Packet was: " + packet);
     }
 
     return true;
   }
 }
 
 
@@ -207,18 +219,22 @@ LocalDebuggerTransport.prototype = {
         dumpn("Got: " + JSON.stringify(aPacket, null, 2));
       }
       this._deepFreeze(aPacket);
       let self = this;
       Services.tm.currentThread.dispatch({run: function() {
         self.other.hooks.onPacket(aPacket);
       }}, 0);
     } catch(e) {
-      dumpn("Error handling incoming packet: " + e + " - " + e.stack);
-      dumpn("Packet was: " + aPacket);
+      let msg = "Error handling incoming packet: " + e + " - " + e.stack;
+      if (Cu.reportError) {
+        Cu.reportError(msg);
+      }
+      dump(msg + "\n");
+      dumpn("Packet was: " + aPacket + "\n");
     }
   },
 
   /**
    * Close the transport.
    */
   close: function LDT_close() {
     if (this.other) {
--- a/toolkit/devtools/webconsole/dbg-webconsole-actors.js
+++ b/toolkit/devtools/webconsole/dbg-webconsole-actors.js
@@ -716,47 +716,31 @@ WebConsoleActor.prototype =
    * @param object aMessage
    *        The original message received from console-api-log-event.
    * @return object
    *         The object that can be sent to the remote client.
    */
   prepareConsoleMessageForRemote:
   function WCA_prepareConsoleMessageForRemote(aMessage)
   {
-    let result = {
-      level: aMessage.level,
-      filename: aMessage.filename,
-      lineNumber: aMessage.lineNumber,
-      functionName: aMessage.functionName,
-      timeStamp: aMessage.timeStamp,
-    };
+    let result = WebConsoleUtils.cloneObject(aMessage);
+    delete result.wrappedJSObject;
+
+    result.arguments = Array.map(aMessage.arguments || [],
+      function(aObj) {
+        return this.createValueGrip(aObj);
+      }, this);
 
-    switch (result.level) {
-      case "trace":
-      case "group":
-      case "groupCollapsed":
-      case "time":
-      case "timeEnd":
-        result.arguments = aMessage.arguments;
-        break;
-      default:
-        result.arguments = Array.map(aMessage.arguments || [],
-          function(aObj) {
-            return this.createValueGrip(aObj);
-          }, this);
-
-        if (result.level == "dir") {
-          result.objectProperties = [];
-          let first = result.arguments[0];
-          if (typeof first == "object" && first && first.inspectable) {
-            let actor = this.getActorByID(first.actor);
-            result.objectProperties = actor.onInspectProperties().properties;
-          }
-        }
-        break;
+    if (result.level == "dir") {
+      result.objectProperties = [];
+      let first = result.arguments[0];
+      if (typeof first == "object" && first && first.inspectable) {
+        let actor = this.getActorByID(first.actor);
+        result.objectProperties = actor.onInspectProperties().properties;
+      }
     }
 
     return result;
   },
 
   /**
    * Find the XUL window that owns the content window.
    *
--- a/toolkit/devtools/webconsole/test/test_consoleapi.html
+++ b/toolkit/devtools/webconsole/test/test_consoleapi.html
@@ -57,17 +57,17 @@ function doConsoleCalls(aState)
       timeStamp: /^\d+$/,
       arguments: [{ type: "null" }],
     },
     {
       level: "trace",
       filename: /test_consoleapi/,
       functionName: "doConsoleCalls",
       timeStamp: /^\d+$/,
-      arguments: [
+      stacktrace: [
         {
           filename: /test_consoleapi/,
           functionName: "doConsoleCalls",
         },
         {
           filename: /test_consoleapi/,
           functionName: "onAttach",
         },