Web Inspector: add a DebugUI context menu item for saving inspector protocol traffic...
authorbburg@apple.com <bburg@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 4 Jan 2016 20:37:10 +0000 (20:37 +0000)
committerbburg@apple.com <bburg@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 4 Jan 2016 20:37:10 +0000 (20:37 +0000)
https://bugs.webkit.org/show_bug.cgi?id=152671

Reviewed by Timothy Hatcher.

Add a new tracer that captures all messages, and debug context menu
items to control whether to capture protocol traffic and export it.
In later patches, a reciprocal "Import..." context menu item will
allow opening saved protocol traces and viewing them in a debug UI
content view for debugging/visualizing protocol traffic.

* UserInterface/Base/Main.js:
* UserInterface/Debug/CapturingProtocolTracer.js: Copied from Source/WebInspectorUI/UserInterface/Protocol/ProtocolTracer.js.

    This tracer saves everything into a flat array. JSON protocol
    messages are saved as escaped strings, in case they are not
    valid JSON. We want to be able to debug such scenarios.

(WebInspector.CapturingProtocolTracer):
(WebInspector.CapturingProtocolTracer.prototype.get trace):
(WebInspector.CapturingProtocolTracer.prototype.logFrontendException):
(WebInspector.CapturingProtocolTracer.prototype.logProtocolError):
(WebInspector.CapturingProtocolTracer.prototype.logFrontendRequest):
(WebInspector.CapturingProtocolTracer.prototype.logDidHandleResponse):
(WebInspector.CapturingProtocolTracer.prototype.logDidHandleEvent):
(WebInspector.CapturingProtocolTracer.prototype._stringifyMessage):
(WebInspector.CapturingProtocolTracer.prototype._processEntry):

* UserInterface/Debug/ProtocolTrace.js: Added.

    This is a dumb container that holds protocol trace data. It will
    be responsible for deserializing saved trace files in later work.

(WebInspector.ProtocolTrace):
(WebInspector.ProtocolTrace.prototype.addEntry):
(WebInspector.ProtocolTrace.prototype.get saveData):
* UserInterface/Main.html:
* UserInterface/Protocol/InspectorBackend.js:
(InspectorBackendClass):

    Simplify the implementation. Now there are one or two tracers
    at any given time. The default tracer handles legacy logging
    behavior and always exists. The custom tracer is installed when
    the "Capture Protocol Traffic" context menu item is toggled.

    Dispatch to the array of active tracers at each trace point.
    Tracers now get the actual JSON message instead of a stringified
    version passed as an argument.

(InspectorBackendClass.prototype.set dumpInspectorProtocolMessages):
(InspectorBackendClass.prototype.get dumpInspectorProtocolMessages):
(InspectorBackendClass.prototype.set dumpInspectorTimeStats):
(InspectorBackendClass.prototype.set customTracer):
(InspectorBackendClass.prototype.get activeTracers):
(InspectorBackendClass.prototype._startOrStopAutomaticTracing):
(InspectorBackendClass.prototype._sendMessageToBackend):
(InspectorBackendClass.prototype._dispatchResponse):
(InspectorBackendClass.prototype._dispatchEvent):
(InspectorBackendClass.prototype.set activeTracer): Deleted.
(InspectorBackendClass.prototype.get activeTracer): Deleted.
* UserInterface/Protocol/LoggingProtocolTracer.js:
(WebInspector.LoggingProtocolTracer.prototype._processEntry):
(WebInspector.LoggingProtocolTracer):
(WebInspector.LoggingProtocolTracer.prototype.logFrontendRequest):
(WebInspector.LoggingProtocolTracer.prototype.logWillHandleResponse):
(WebInspector.LoggingProtocolTracer.prototype.logDidHandleResponse):
(WebInspector.LoggingProtocolTracer.prototype.logWillHandleEvent):
(WebInspector.LoggingProtocolTracer.prototype.logDidHandleEvent):
* UserInterface/Protocol/ProtocolTracer.js:
(WebInspector.ProtocolTracer.prototype.logFrontendException):
(WebInspector.ProtocolTracer.prototype.logProtocolError):
(WebInspector.ProtocolTracer.prototype.logFrontendRequest):
(WebInspector.ProtocolTracer.prototype.logWillHandleResponse):
(WebInspector.ProtocolTracer.prototype.logDidHandleResponse):
(WebInspector.ProtocolTracer.prototype.logWillHandleEvent):
(WebInspector.ProtocolTracer.prototype.logDidHandleEvent):

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@194546 268f45cc-cd09-0410-ab3c-d52691b4dbfc

Source/WebInspectorUI/ChangeLog
Source/WebInspectorUI/UserInterface/Base/Main.js
Source/WebInspectorUI/UserInterface/Debug/CapturingProtocolTracer.js [new file with mode: 0644]
Source/WebInspectorUI/UserInterface/Debug/ProtocolTrace.js [new file with mode: 0644]
Source/WebInspectorUI/UserInterface/Main.html
Source/WebInspectorUI/UserInterface/Protocol/InspectorBackend.js
Source/WebInspectorUI/UserInterface/Protocol/LoggingProtocolTracer.js
Source/WebInspectorUI/UserInterface/Protocol/ProtocolTracer.js

index 7f3c46d..e98e25c 100644 (file)
@@ -1,3 +1,82 @@
+2016-01-04  Brian Burg  <bburg@apple.com>
+
+        Web Inspector: add a DebugUI context menu item for saving inspector protocol traffic to file
+        https://bugs.webkit.org/show_bug.cgi?id=152671
+
+        Reviewed by Timothy Hatcher.
+
+        Add a new tracer that captures all messages, and debug context menu
+        items to control whether to capture protocol traffic and export it.
+        In later patches, a reciprocal "Import..." context menu item will
+        allow opening saved protocol traces and viewing them in a debug UI
+        content view for debugging/visualizing protocol traffic.
+
+        * UserInterface/Base/Main.js:
+        * UserInterface/Debug/CapturingProtocolTracer.js: Copied from Source/WebInspectorUI/UserInterface/Protocol/ProtocolTracer.js.
+
+            This tracer saves everything into a flat array. JSON protocol
+            messages are saved as escaped strings, in case they are not
+            valid JSON. We want to be able to debug such scenarios.
+
+        (WebInspector.CapturingProtocolTracer):
+        (WebInspector.CapturingProtocolTracer.prototype.get trace):
+        (WebInspector.CapturingProtocolTracer.prototype.logFrontendException):
+        (WebInspector.CapturingProtocolTracer.prototype.logProtocolError):
+        (WebInspector.CapturingProtocolTracer.prototype.logFrontendRequest):
+        (WebInspector.CapturingProtocolTracer.prototype.logDidHandleResponse):
+        (WebInspector.CapturingProtocolTracer.prototype.logDidHandleEvent):
+        (WebInspector.CapturingProtocolTracer.prototype._stringifyMessage):
+        (WebInspector.CapturingProtocolTracer.prototype._processEntry):
+
+        * UserInterface/Debug/ProtocolTrace.js: Added.
+
+            This is a dumb container that holds protocol trace data. It will
+            be responsible for deserializing saved trace files in later work.
+
+        (WebInspector.ProtocolTrace):
+        (WebInspector.ProtocolTrace.prototype.addEntry):
+        (WebInspector.ProtocolTrace.prototype.get saveData):
+        * UserInterface/Main.html:
+        * UserInterface/Protocol/InspectorBackend.js:
+        (InspectorBackendClass):
+
+            Simplify the implementation. Now there are one or two tracers
+            at any given time. The default tracer handles legacy logging
+            behavior and always exists. The custom tracer is installed when
+            the "Capture Protocol Traffic" context menu item is toggled.
+
+            Dispatch to the array of active tracers at each trace point.
+            Tracers now get the actual JSON message instead of a stringified
+            version passed as an argument.
+
+        (InspectorBackendClass.prototype.set dumpInspectorProtocolMessages):
+        (InspectorBackendClass.prototype.get dumpInspectorProtocolMessages):
+        (InspectorBackendClass.prototype.set dumpInspectorTimeStats):
+        (InspectorBackendClass.prototype.set customTracer):
+        (InspectorBackendClass.prototype.get activeTracers):
+        (InspectorBackendClass.prototype._startOrStopAutomaticTracing):
+        (InspectorBackendClass.prototype._sendMessageToBackend):
+        (InspectorBackendClass.prototype._dispatchResponse):
+        (InspectorBackendClass.prototype._dispatchEvent):
+        (InspectorBackendClass.prototype.set activeTracer): Deleted.
+        (InspectorBackendClass.prototype.get activeTracer): Deleted.
+        * UserInterface/Protocol/LoggingProtocolTracer.js:
+        (WebInspector.LoggingProtocolTracer.prototype._processEntry):
+        (WebInspector.LoggingProtocolTracer):
+        (WebInspector.LoggingProtocolTracer.prototype.logFrontendRequest):
+        (WebInspector.LoggingProtocolTracer.prototype.logWillHandleResponse):
+        (WebInspector.LoggingProtocolTracer.prototype.logDidHandleResponse):
+        (WebInspector.LoggingProtocolTracer.prototype.logWillHandleEvent):
+        (WebInspector.LoggingProtocolTracer.prototype.logDidHandleEvent):
+        * UserInterface/Protocol/ProtocolTracer.js:
+        (WebInspector.ProtocolTracer.prototype.logFrontendException):
+        (WebInspector.ProtocolTracer.prototype.logProtocolError):
+        (WebInspector.ProtocolTracer.prototype.logFrontendRequest):
+        (WebInspector.ProtocolTracer.prototype.logWillHandleResponse):
+        (WebInspector.ProtocolTracer.prototype.logDidHandleResponse):
+        (WebInspector.ProtocolTracer.prototype.logWillHandleEvent):
+        (WebInspector.ProtocolTracer.prototype.logDidHandleEvent):
+
 2016-01-04  Devin Rousso  <dcrousso+webkit@gmail.com>
 
         Web Inspector: Comma separated values in the Visual sidebar are appended with )
index 35b7000..0b36b11 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2013-2014 Apple Inc. All rights reserved.
+ * Copyright (C) 2013-2016 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -1378,6 +1378,23 @@ WebInspector._contextMenuRequested = function(event)
         proposedContextMenu.appendItem(WebInspector.unlocalizedString("Reload Web Inspector"), () => {
             window.location.reload();
         });
+
+        let protocolSubMenu = proposedContextMenu.appendSubMenuItem(WebInspector.unlocalizedString("Protocol Debugging"), null, false);
+        let isCapturingTraffic = InspectorBackend.activeTracer instanceof WebInspector.CapturingProtocolTracer;
+
+        protocolSubMenu.appendCheckboxItem(WebInspector.unlocalizedString("Capture Trace"), () => {
+            if (isCapturingTraffic)
+                InspectorBackend.activeTracer = null;
+            else
+                InspectorBackend.activeTracer = new WebInspector.CapturingProtocolTracer;
+        }, isCapturingTraffic);
+
+        protocolSubMenu.appendSeparator();
+
+        protocolSubMenu.appendItem(WebInspector.unlocalizedString("Export Trace\u2014"), () => {
+            const forceSaveAs = true;
+            WebInspector.saveDataToFile(InspectorBackend.activeTracer.trace.saveData, forceSaveAs);
+        }, !isCapturingTraffic);
     } else {
         const onlyExisting = true;
         proposedContextMenu = WebInspector.ContextMenu.createFromEvent(event, onlyExisting);
diff --git a/Source/WebInspectorUI/UserInterface/Debug/CapturingProtocolTracer.js b/Source/WebInspectorUI/UserInterface/Debug/CapturingProtocolTracer.js
new file mode 100644 (file)
index 0000000..f44754a
--- /dev/null
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2016 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+WebInspector.CapturingProtocolTracer = class CapturingProtocolTracer extends WebInspector.ProtocolTracer
+{
+    constructor()
+    {
+        super();
+
+        this._trace = new WebInspector.ProtocolTrace;
+    }
+
+    // Public
+
+    get trace()
+    {
+        return this._trace;
+    }
+
+    logFrontendException(message, exception)
+    {
+        this._processEntry({type: "exception", message: this._stringifyMessage(message), exception});
+    }
+
+    logProtocolError(message, error)
+    {
+        this._processEntry({type: "error", message: this._stringifyMessage(message), error});
+    }
+
+    logFrontendRequest(message)
+    {
+        this._processEntry({type: "request", message: this._stringifyMessage(message)});
+    }
+
+    logDidHandleResponse(message, timings = null)
+    {
+        let entry = {type: "response", message: this._stringifyMessage(message)};
+        if (timings)
+            entry.timings = Object.shallowCopy(timings);
+
+        this._processEntry(entry);
+    }
+
+    logDidHandleEvent(message, timings = null)
+    {
+        let entry = {type: "event", message: this._stringifyMessage(message)};
+        if (timings)
+            entry.timings = Object.shallowCopy(timings);
+
+        this._processEntry(entry);
+    }
+
+    _stringifyMessage(message)
+    {
+        try {
+            return JSON.stringify(message);
+        } catch (e) {
+            console.error("couldn't stringify object:", message, e);
+            return {};
+        }
+    }
+
+    _processEntry(entry)
+    {
+        this._trace.addEntry(entry);
+    }
+};
diff --git a/Source/WebInspectorUI/UserInterface/Debug/ProtocolTrace.js b/Source/WebInspectorUI/UserInterface/Debug/ProtocolTrace.js
new file mode 100644 (file)
index 0000000..a26a965
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2016 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+WebInspector.ProtocolTrace = class ProtocolTrace extends WebInspector.Object
+{
+    constructor()
+    {
+        super();
+
+        this._entries = [];
+    }
+
+    // Public
+
+    addEntry(entry) {
+        this._entries.push(entry);
+    }
+
+    get saveData() {
+        let now = new Date();
+        let YYYY = now.getFullYear();
+        let MM = now.getMonth() + 1;
+        let DD = now.getDate();
+        let hh = now.getHours();
+        let mm = now.getMinutes();
+        let ss = now.getSeconds();
+
+        // This follows the file name of screen shots on OS X (en-US):
+        // "Protocol Trace 2015-12-31 at 12.43.04.json".
+        // When the Intl API is implemented, we can do a better job.
+        let filename = WebInspector.unlocalizedString(`Protocol Trace at ${YYYY}-${MM}-${DD} ${hh}.${mm}.${ss}.json`);
+        return {url: "web-inspector:///" + encodeURIComponent(filename), content: JSON.stringify(this._entries)};
+    }
+};
index 22f995c..b9e5d35 100644 (file)
     <script src="Base/Main.js"></script>
 
     <script src="Debug/Bootstrap.js"></script>
+    <script src="Debug/CapturingProtocolTracer.js"></script>
+    <script src="Debug/ProtocolTrace.js"></script>
 
     <script>
         WebInspector.loaded();
index 3431308..32b1dc5 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2011 Google Inc. All rights reserved.
- * Copyright (C) 2013, 2015 Apple Inc. All rights reserved.
+ * Copyright (C) 2013, 2015, 2016 Apple Inc. All rights reserved.
  * Copyright (C) 2014 University of Washington.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -38,8 +38,10 @@ InspectorBackendClass = class InspectorBackendClass
         this._pendingResponses = new Map;
         this._agents = {};
         this._deferredScripts = [];
-        this._activeTracer = null;
-        this._automaticTracer = null;
+
+        this._customTracer = null;
+        this._defaultTracer = new WebInspector.LoggingProtocolTracer;
+        this._activeTracers = [this._defaultTracer];
 
         this._dumpInspectorTimeStats = false;
 
@@ -59,16 +61,12 @@ InspectorBackendClass = class InspectorBackendClass
         let setting = WebInspector.autoLogProtocolMessagesSetting;
         setting.value = value;
 
-        if (this.activeTracer !== this._automaticTracer)
-            return;
-
-        if (this.activeTracer)
-            this.activeTracer.dumpMessagesToConsole = value;
+        this._defaultTracer.dumpMessagesToConsole = value;
     }
 
     get dumpInspectorProtocolMessages()
     {
-        return !!this._automaticTracer;
+        return WebInspector.autoLogProtocolMessagesSetting.value;
     }
 
     set dumpInspectorTimeStats(value)
@@ -76,11 +74,7 @@ InspectorBackendClass = class InspectorBackendClass
         if (!this.dumpInspectorProtocolMessages)
             this.dumpInspectorProtocolMessages = true;
 
-        if (this.activeTracer !== this._automaticTracer)
-            return;
-
-        if (this.activeTracer)
-            this.activeTracer.dumpTimingDataToConsole = value;
+        this._defaultTracer.dumpTimingDataToConsole = value;
     }
 
     get dumpInspectorTimeStats()
@@ -88,40 +82,36 @@ InspectorBackendClass = class InspectorBackendClass
         return this._dumpInspectorTimeStats;
     }
 
-    set activeTracer(tracer)
+    set customTracer(tracer)
     {
-        console.assert(!tracer || tracer instanceof WebInspector.ProtocolTracer);
+        console.assert(!tracer || tracer instanceof WebInspector.ProtocolTracer, tracer);
+        console.assert(!tracer || tracer !== this._defaultTracer, tracer);
 
         // Bail early if no state change is to be made.
-        if (!tracer && !this._activeTracer)
+        if (!tracer && !this._customTracer)
             return;
 
-        if (tracer === this._activeTracer)
+        if (tracer === this._customTracer)
             return;
 
-        // Don't allow an automatic tracer to dislodge a custom tracer.
-        if (this._activeTracer && tracer === this._automaticTracer)
+        if (tracer === this._defaultTracer)
             return;
 
-        if (this.activeTracer)
-            this.activeTracer.logFinished();
+        if (this._customTracer)
+            this._customTracer.logFinished();
 
-        if (this._activeTracer === this._automaticTracer)
-            this._automaticTracer = null;
+        this._customTracer = tracer;
+        this._activeTracers = [this._defaultTracer];
 
-        this._activeTracer = tracer;
-        if (this.activeTracer)
-            this.activeTracer.logStarted();
-        else {
-            // If the custom tracer was removed and automatic tracing is enabled,
-            // then create a new automatic tracer and install it in its place.
-            this._startOrStopAutomaticTracing();
+        if (this._customTracer) {
+            this._customTracer.logStarted();
+            this._activeTracers.push(this._customTracer);
         }
     }
 
-    get activeTracer()
+    get activeTracers()
     {
-        return this._activeTracer || null;
+        return this._activeTracers;
     }
 
     registerCommand(qualifiedName, callSignature, replySignature)
@@ -187,24 +177,8 @@ InspectorBackendClass = class InspectorBackendClass
 
     _startOrStopAutomaticTracing()
     {
-        let setting = WebInspector.autoLogProtocolMessagesSetting;
-
-        // Bail if there is no state transition to be made.
-        if (!(setting.value ^ !!this.activeTracer))
-            return;
-
-        if (!setting.value) {
-            if (this.activeTracer === this._automaticTracer)
-                this.activeTracer = null;
-
-            this._automaticTracer = null;
-        } else {
-            this._automaticTracer = new WebInspector.LoggingProtocolTracer;
-            this._automaticTracer.dumpMessagesToConsole = this.dumpInspectorProtocolMessages;
-            this._automaticTracer.dumpTimingDataToConsole = this.dumpTimingDataToConsole;
-            // This will be ignored if a custom tracer is installed.
-            this.activeTracer = this._automaticTracer;
-        }
+        this._defaultTracer.dumpMessagesToConsole = this.dumpInspectorProtocolMessages;
+        this._defaultTracer.dumpTimingDataToConsole = this.dumpTimingDataToConsole;
     }
 
     _agentForDomain(domainName)
@@ -267,11 +241,10 @@ InspectorBackendClass = class InspectorBackendClass
 
     _sendMessageToBackend(messageObject)
     {
-        let stringifiedMessage = JSON.stringify(messageObject);
-        if (this.activeTracer)
-            this.activeTracer.logFrontendRequest(stringifiedMessage);
+        for (let tracer of this.activeTracers)
+            tracer.logFrontendRequest(messageObject);
 
-        InspectorFrontendHost.sendMessageToBackend(stringifiedMessage);
+        InspectorFrontendHost.sendMessageToBackend(JSON.stringify(messageObject));
     }
 
     _dispatchResponse(messageObject)
@@ -286,14 +259,12 @@ InspectorBackendClass = class InspectorBackendClass
         let sequenceId = messageObject["id"];
         console.assert(this._pendingResponses.has(sequenceId), sequenceId, this._pendingResponses);
 
-        let responseData = this._pendingResponses.take(sequenceId);
+        let responseData = this._pendingResponses.take(sequenceId) || {};
         let {command, callback, promise} = responseData;
 
-        let processingStartTimestamp;
-        if (this.activeTracer) {
-            processingStartTimestamp = timestamp();
-            this.activeTracer.logWillHandleResponse(JSON.stringify(messageObject));
-        }
+        let processingStartTimestamp = timestamp();
+        for (let tracer of this.activeTracers)
+            tracer.logWillHandleResponse(messageObject);
 
         if (typeof callback === "function")
             this._dispatchResponseToCallback(command, messageObject, callback);
@@ -302,11 +273,11 @@ InspectorBackendClass = class InspectorBackendClass
         else
             console.error("Received a command response without a corresponding callback or promise.", messageObject, command);
 
-        if (this.activeTracer) {
-            let processingTime = (timestamp() - processingStartTimestamp).toFixed(3);
-            let roundTripTime = (processingStartTimestamp - responseData.sendRequestTimestamp).toFixed(3);
-            this.activeTracer.logDidHandleResponse(JSON.stringify(messageObject), {rtt: roundTripTime, dispatch: processingTime});
-        }
+        let processingTime = (timestamp() - processingStartTimestamp).toFixed(3);
+        let roundTripTime = (processingStartTimestamp - responseData.sendRequestTimestamp).toFixed(3);
+
+        for (let tracer of this.activeTracers)
+            tracer.logDidHandleResponse(messageObject, {rtt: roundTripTime, dispatch: processingTime});
 
         if (this._deferredScripts.length && !this._pendingResponses.size)
             this._flushPendingScripts();
@@ -363,24 +334,21 @@ InspectorBackendClass = class InspectorBackendClass
         if (messageObject["params"])
             eventArguments = event.parameterNames.map((name) => messageObject["params"][name]);
 
-        let processingStartTimestamp;
-        if (this.activeTracer) {
-            processingStartTimestamp = timestamp();
-            this.activeTracer.logWillHandleEvent(JSON.stringify(messageObject));
-        }
+        let processingStartTimestamp = timestamp();
+        for (let tracer of this.activeTracers)
+            tracer.logWillHandleEvent(messageObject);
 
         try {
             agent.dispatchEvent(eventName, eventArguments);
         } catch (e) {
             console.error("Uncaught exception in inspector page while handling event " + qualifiedName, e);
-            if (this.activeTracer)
-                this.activeTracer.logFrontendException(JSON.stringify(messageObject), e);
+            for (let tracer of this.activeTracers)
+                tracer.logFrontendException(messageObject, e);
         }
 
-        if (this.activeTracer) {
-            let processingTime = (timestamp() - processingStartTimestamp).toFixed(3);
-            this.activeTracer.logDidHandleEvent(JSON.stringify(messageObject), {dispatch: processingTime});
-        }
+        let processingDuration = (timestamp() - processingStartTimestamp).toFixed(3);
+        for (let tracer of this.activeTracers)
+            tracer.logDidHandleEvent(messageObject, {dispatch: processingDuration});
     }
 
     _reportProtocolError(messageObject)
index d9f8fea..2d13dcc 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2015 Apple Inc. All rights reserved.
+ * Copyright (C) 2015, 2016 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -68,23 +68,17 @@ WebInspector.LoggingProtocolTracer = class LoggingProtocolTracer extends WebInsp
 
     logFrontendRequest(message)
     {
-        console.assert(typeof message === "string", "Must stringify messages to avoid leaking all JSON protocol messages.")
-
         this._processEntry({type: "request", message});
     }
 
     logWillHandleResponse(message)
     {
-        console.assert(typeof message === "string", "Must stringify messages to avoid leaking all JSON protocol messages.")
-
         let entry = {type: "response", message};
         this._processEntry(entry);
     }
 
     logDidHandleResponse(message, timings = null)
     {
-        console.assert(typeof message === "string", "Must stringify messages to avoid leaking all JSON protocol messages.")
-
         let entry = {type: "response", message};
         if (timings)
             entry.timings = Object.shallowCopy(timings);
@@ -94,16 +88,12 @@ WebInspector.LoggingProtocolTracer = class LoggingProtocolTracer extends WebInsp
 
     logWillHandleEvent(message)
     {
-        console.assert(typeof message === "string", "Must stringify messages to avoid leaking all JSON protocol messages.")
-
         let entry = {type: "event", message};
         this._processEntry(entry);
     }
 
     logDidHandleEvent(message, timings = null)
     {
-        console.assert(typeof message === "string", "Must stringify messages to avoid leaking all JSON protocol messages.")
-
         let entry = {type: "event", message};
         if (timings)
             entry.timings = Object.shallowCopy(timings);
@@ -119,6 +109,6 @@ WebInspector.LoggingProtocolTracer = class LoggingProtocolTracer extends WebInsp
             else if (entry.timings.dispatch)
                 this._logToConsole(`time-stats: Handling: ${entry.timings.dispatch || NaN}ms`);
         } else if (this._dumpMessagesToConsole && !entry.timings)
-            this._logToConsole(`${entry.type}: ${entry.message}`);
+            this._logToConsole(`${entry.type}: ${JSON.stringify(entry.message)}`);
     }
 };
index 0d16c21..c186bd2 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2015 Apple Inc. All rights reserved.
+ * Copyright (C) 2015, 2016 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -34,50 +34,36 @@ WebInspector.ProtocolTracer = class ProtocolTracer extends WebInspector.Object
 
     logFrontendException(message, exception)
     {
-        console.assert(typeof message === "string", "Must stringify messages to avoid leaking all JSON protocol messages.")
-
         // To be overridden by subclasses.
     }
 
     logProtocolError(message, error)
     {
-        console.assert(typeof message === "string", "Must stringify messages to avoid leaking all JSON protocol messages.")
-
         // To be overridden by subclasses.
     }
 
     logFrontendRequest(message)
     {
-        console.assert(typeof message === "string", "Must stringify messages to avoid leaking all JSON protocol messages.")
-
         // To be overridden by subclasses.
     }
 
     logWillHandleResponse(message)
     {
-        console.assert(typeof message === "string", "Must stringify messages to avoid leaking all JSON protocol messages.")
-
         // To be overridden by subclasses.
     }
 
     logDidHandleResponse(message, timings = null)
     {
-        console.assert(typeof message === "string", "Must stringify messages to avoid leaking all JSON protocol messages.")
-
         // To be overridden by subclasses.
     }
 
     logWillHandleEvent(message)
     {
-        console.assert(typeof message === "string", "Must stringify messages to avoid leaking all JSON protocol messages.")
-
         // To be overridden by subclasses.
     }
 
     logDidHandleEvent(message, timings = null)
     {
-        console.assert(typeof message === "string", "Must stringify messages to avoid leaking all JSON protocol messages.")
-
         // To be overridden by subclasses.
     }