Changeset 193870 in webkit


Ignore:
Timestamp:
Dec 9, 2015 2:45:21 PM (8 years ago)
Author:
BJ Burg
Message:

Web Inspector: control whether to collect and dump protocol messages using a WebInspector.Setting
https://bugs.webkit.org/show_bug.cgi?id=151635

Reviewed by Timothy Hatcher.

When closing and reopening the inspector, the setting for whether
to dump protocol messages should be persisted. Otherwise, enabling
dumping from the debug-only UI will miss the initial flood of
messages that are processed when the Inspector loads initial data.

To support a persistent setting, and build some infrastructure for
more advanced uses of collected protocol messages, this patch adds
a new object to trace protocol events. It gets callbacks for each
and implements the console-dumping functionality previously baked in
to InspectorBackend.

In follow-up patches, other protocol tracers will be added to save
protocol data to disk, marshall it to a higher inspection level,
or provide more fine-grained control over what is logged.

This change moves Setting.js into the Base/ directory,
since it is used by Views, Models, and now Protocol classes.

  • UserInterface/Base/Setting.js: Renamed from Source/WebInspectorUI/UserInterface/Models/Setting.js.

(WebInspector.Setting):
(WebInspector.Setting.prototype.get name):
(WebInspector.Setting.prototype.get value):
(WebInspector.Setting.prototype.set value):

  • UserInterface/Main.html:
  • UserInterface/Protocol/InspectorBackend.js:

(InspectorBackendClass):
(InspectorBackendClass.prototype.set dumpInspectorProtocolMessages):
(InspectorBackendClass.prototype.get dumpInspectorProtocolMessages):

We still want to support the legacy way to enable dumping:
InspectorBackend.dumpInspectorProtocolMessages = true. This
is because some tests always use it, and it's easier to set this
flag in a custom Bootstrap.js file than to configure the Setting.

(InspectorBackendClass.prototype.set dumpInspectorTimeStats):
(InspectorBackendClass.prototype.get dumpInspectorTimeStats):

We still want to support the legacy way to enable dumping:
InspectorBackend.dumpInspectorTimeStats = true. This is
because MessageDispatcher checks this flag for its logging.

(InspectorBackendClass.prototype.set activeTracer):
(InspectorBackendClass.prototype.get activeTracer):

Set the active tracer, finalizing and removing any active tracer
if one exists. If removing a custom tracer (setting to null), then
re-sync activeTracer with the automatic tracing Setting.

(InspectorBackendClass.prototype.dispatch):
(InspectorBackendClass.prototype._startOrStopAutomaticTracing):

Sync the Setting with activeTracer. If an custom tracer is active,
don't replace it with the automatic logging tracer.

(InspectorBackendClass.prototype._sendCommandToBackendWithCallback):
(InspectorBackendClass.prototype._sendCommandToBackendExpectingPromise):
(InspectorBackendClass.prototype._sendMessageToBackend):
(InspectorBackendClass.prototype._dispatchResponse):
(InspectorBackendClass.prototype._dispatchEvent):
(InspectorBackendClass.prototype._flushPendingScripts):

  • UserInterface/Protocol/LoggingProtocolTracer.js: Added.

(WebInspector.LoggingProtocolTracer):
(WebInspector.LoggingProtocolTracer.prototype.set dumpMessagesToConsole):
(WebInspector.LoggingProtocolTracer.prototype.get dumpMessagesToConsole):
(WebInspector.LoggingProtocolTracer.prototype.set dumpTimingDataToConsole):
(WebInspector.LoggingProtocolTracer.prototype.get dumpTimingDataToConsole):
(WebInspector.LoggingProtocolTracer.prototype.logFrontendException):
(WebInspector.LoggingProtocolTracer.prototype.logProtocolError):
(WebInspector.LoggingProtocolTracer.prototype.logFrontendRequest):
(WebInspector.LoggingProtocolTracer.prototype.logWillHandleResponse):
(WebInspector.LoggingProtocolTracer.prototype.logDidHandleResponse):
(WebInspector.LoggingProtocolTracer.prototype.logWillHandleEvent):
(WebInspector.LoggingProtocolTracer.prototype.logDidHandleEvent):
(WebInspector.LoggingProtocolTracer.prototype._processEntry):

  • UserInterface/Protocol/ProtocolTracer.js: Added.

(WebInspector.ProtocolTracer.prototype.logStarted):
(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): (WebInspector.ProtocolTracer.prototype.logFinished):
(WebInspector.ProtocolTracer):

  • UserInterface/Test.html:
Location:
trunk/Source/WebInspectorUI
Files:
2 added
4 edited
1 moved

Legend:

Unmodified
Added
Removed
  • trunk/Source/WebInspectorUI/ChangeLog

    r193858 r193870  
     12015-12-09  Brian Burg  <bburg@apple.com>
     2
     3        Web Inspector: control whether to collect and dump protocol messages using a WebInspector.Setting
     4        https://bugs.webkit.org/show_bug.cgi?id=151635
     5
     6        Reviewed by Timothy Hatcher.
     7
     8        When closing and reopening the inspector, the setting for whether
     9        to dump protocol messages should be persisted. Otherwise, enabling
     10        dumping from the debug-only UI will miss the initial flood of
     11        messages that are processed when the Inspector loads initial data.
     12
     13        To support a persistent setting, and build some infrastructure for
     14        more advanced uses of collected protocol messages, this patch adds
     15        a new object to trace protocol events. It gets callbacks for each
     16        and implements the console-dumping functionality previously baked in
     17        to InspectorBackend.
     18
     19        In follow-up patches, other protocol tracers will be added to save
     20        protocol data to disk, marshall it to a higher inspection level,
     21        or provide more fine-grained control over what is logged.
     22
     23        This change moves Setting.js into the Base/ directory,
     24        since it is used by Views, Models, and now Protocol classes.
     25
     26        * UserInterface/Base/Setting.js: Renamed from Source/WebInspectorUI/UserInterface/Models/Setting.js.
     27        (WebInspector.Setting):
     28        (WebInspector.Setting.prototype.get name):
     29        (WebInspector.Setting.prototype.get value):
     30        (WebInspector.Setting.prototype.set value):
     31        * UserInterface/Main.html:
     32        * UserInterface/Protocol/InspectorBackend.js:
     33        (InspectorBackendClass):
     34        (InspectorBackendClass.prototype.set dumpInspectorProtocolMessages):
     35        (InspectorBackendClass.prototype.get dumpInspectorProtocolMessages):
     36
     37            We still want to support the legacy way to enable dumping:
     38            `InspectorBackend.dumpInspectorProtocolMessages = true`. This
     39            is because some tests always use it, and it's easier to set this
     40            flag in a custom Bootstrap.js file than to configure the Setting.
     41
     42        (InspectorBackendClass.prototype.set dumpInspectorTimeStats):
     43        (InspectorBackendClass.prototype.get dumpInspectorTimeStats):
     44
     45            We still want to support the legacy way to enable dumping:
     46            `InspectorBackend.dumpInspectorTimeStats = true`. This is
     47            because MessageDispatcher checks this flag for its logging.
     48
     49        (InspectorBackendClass.prototype.set activeTracer):
     50        (InspectorBackendClass.prototype.get activeTracer):
     51
     52            Set the active tracer, finalizing and removing any active tracer
     53            if one exists. If removing a custom tracer (setting to null), then
     54            re-sync activeTracer with the automatic tracing Setting.
     55
     56        (InspectorBackendClass.prototype.dispatch):
     57        (InspectorBackendClass.prototype._startOrStopAutomaticTracing):
     58
     59            Sync the Setting with activeTracer. If an custom tracer is active,
     60            don't replace it with the automatic logging tracer.
     61
     62        (InspectorBackendClass.prototype._sendCommandToBackendWithCallback):
     63        (InspectorBackendClass.prototype._sendCommandToBackendExpectingPromise):
     64        (InspectorBackendClass.prototype._sendMessageToBackend):
     65        (InspectorBackendClass.prototype._dispatchResponse):
     66        (InspectorBackendClass.prototype._dispatchEvent):
     67        (InspectorBackendClass.prototype._flushPendingScripts):
     68        * UserInterface/Protocol/LoggingProtocolTracer.js: Added.
     69        (WebInspector.LoggingProtocolTracer):
     70        (WebInspector.LoggingProtocolTracer.prototype.set dumpMessagesToConsole):
     71        (WebInspector.LoggingProtocolTracer.prototype.get dumpMessagesToConsole):
     72        (WebInspector.LoggingProtocolTracer.prototype.set dumpTimingDataToConsole):
     73        (WebInspector.LoggingProtocolTracer.prototype.get dumpTimingDataToConsole):
     74        (WebInspector.LoggingProtocolTracer.prototype.logFrontendException):
     75        (WebInspector.LoggingProtocolTracer.prototype.logProtocolError):
     76        (WebInspector.LoggingProtocolTracer.prototype.logFrontendRequest):
     77        (WebInspector.LoggingProtocolTracer.prototype.logWillHandleResponse):
     78        (WebInspector.LoggingProtocolTracer.prototype.logDidHandleResponse):
     79        (WebInspector.LoggingProtocolTracer.prototype.logWillHandleEvent):
     80        (WebInspector.LoggingProtocolTracer.prototype.logDidHandleEvent):
     81        (WebInspector.LoggingProtocolTracer.prototype._processEntry):
     82        * UserInterface/Protocol/ProtocolTracer.js: Added.
     83        (WebInspector.ProtocolTracer.prototype.logStarted):
     84        (WebInspector.ProtocolTracer.prototype.logFrontendException):
     85        (WebInspector.ProtocolTracer.prototype.logProtocolError):
     86        (WebInspector.ProtocolTracer.prototype.logFrontendRequest):
     87        (WebInspector.ProtocolTracer.prototype.logWillHandleResponse):
     88        (WebInspector.ProtocolTracer.prototype.logDidHandleResponse):
     89        (WebInspector.ProtocolTracer.prototype.logWillHandleEvent):
     90        (WebInspector.ProtocolTracer.prototype.logDidHandleEvent):        (WebInspector.ProtocolTracer.prototype.logFinished):
     91        (WebInspector.ProtocolTracer):
     92        * UserInterface/Test.html:
     93
    1942015-12-09  Brian Burg  <bburg@apple.com>
    295
  • trunk/Source/WebInspectorUI/UserInterface/Base/Setting.js

    r193867 r193870  
    3838        this._name = name;
    3939
    40         let inspectionLevel = InspectorFrontendHost.inspectionLevel();
     40        let inspectionLevel = InspectorFrontendHost ? InspectorFrontendHost.inspectionLevel() : 1;
    4141        let levelString = inspectionLevel > 1 ? "-" + inspectionLevel : "";
    4242        this._localStorageKey = `com.apple.WebInspector${levelString}.${name}`;
  • trunk/Source/WebInspectorUI/UserInterface/Main.html

    r193646 r193870  
    225225    <script src="Base/URLUtilities.js"></script>
    226226    <script src="Base/Utilities.js"></script>
     227    <script src="Base/Setting.js"></script>
     228
     229    <script src="Protocol/ProtocolTracer.js"></script>
     230    <script src="Protocol/LoggingProtocolTracer.js"></script>
    227231
    228232    <script src="Protocol/ApplicationCacheObserver.js"></script>
     
    329333    <script src="Models/ScriptSyntaxTree.js"></script>
    330334    <script src="Models/ScriptTimelineRecord.js"></script>
    331     <script src="Models/Setting.js"></script>
    332335    <script src="Models/SourceCodePosition.js"></script>
    333336    <script src="Models/SourceCodeRevision.js"></script>
  • trunk/Source/WebInspectorUI/UserInterface/Protocol/InspectorBackend.js

    r190839 r193870  
    3939        this._agents = {};
    4040        this._deferredScripts = [];
    41 
    42         this.dumpInspectorTimeStats = false;
    43         this.dumpInspectorProtocolMessages = false;
    44         this.warnForLongMessageHandling = false;
    45         this.longMessageHandlingThreshold = 10; // milliseconds.
    46 
    47         this._log = window.InspectorTest ? InspectorFrontendHost.unbufferedLog.bind(InspectorFrontendHost) : console.log.bind(console);
     41        this._activeTracer = null;
     42        this._automaticTracer = null;
     43
     44        this._dumpInspectorTimeStats = false;
     45
     46        let setting = WebInspector.autoLogProtocolMessagesSetting = new WebInspector.Setting("auto-collect-protocol-messages", false);
     47        setting.addEventListener(WebInspector.Setting.Event.Changed, this._startOrStopAutomaticTracing.bind(this))
     48        this._startOrStopAutomaticTracing();
    4849    }
    4950
    5051    // Public
     52
     53    // It's still possible to set this flag on InspectorBackend to just
     54    // dump protocol traffic as it happens. For more complex uses of
     55    // protocol data, install a subclass of WebInspector.ProtocolTracer.
     56    set dumpInspectorProtocolMessages(value)
     57    {
     58        // Implicitly cause automatic logging to start if it's allowed.
     59        let setting = WebInspector.autoLogProtocolMessagesSetting;
     60        setting.value = value;
     61
     62        if (this.activeTracer !== this._automaticTracer)
     63            return;
     64
     65        if (this.activeTracer)
     66            this.activeTracer.dumpMessagesToConsole = value;
     67    }
     68
     69    get dumpInspectorProtocolMessages()
     70    {
     71        return !!this._automaticTracer;
     72    }
     73
     74    set dumpInspectorTimeStats(value)
     75    {
     76        if (!this.dumpInspectorProtocolMessages)
     77            this.dumpInspectorProtocolMessages = true;
     78
     79        if (this.activeTracer !== this._automaticTracer)
     80            return;
     81
     82        if (this.activeTracer)
     83            this.activeTracer.dumpTimingDataToConsole = value;
     84    }
     85
     86    get dumpInspectorTimeStats()
     87    {
     88        return this._dumpInspectorTimeStats;
     89    }
     90
     91    set activeTracer(tracer)
     92    {
     93        console.assert(!tracer || tracer instanceof WebInspector.ProtocolTracer);
     94
     95        // Bail early if no state change is to be made.
     96        if (!tracer && !this._activeTracer)
     97            return;
     98
     99        if (tracer === this._activeTracer)
     100            return;
     101
     102        // Don't allow an automatic tracer to dislodge a custom tracer.
     103        if (this._activeTracer && tracer === this._automaticTracer)
     104            return;
     105
     106        if (this.activeTracer)
     107            this.activeTracer.logFinished();
     108
     109        if (this._activeTracer === this._automaticTracer)
     110            this._automaticTracer = null;
     111
     112        this._activeTracer = tracer;
     113        if (this.activeTracer)
     114            this.activeTracer.logStarted();
     115        else {
     116            // If the custom tracer was removed and automatic tracing is enabled,
     117            // then create a new automatic tracer and install it in its place.
     118            this._startOrStopAutomaticTracing();
     119        }
     120    }
     121
     122    get activeTracer()
     123    {
     124        return this._activeTracer || null;
     125    }
    51126
    52127    registerCommand(qualifiedName, callSignature, replySignature)
     
    79154    dispatch(message)
    80155    {
    81         if (this.dumpInspectorProtocolMessages)
    82             this._log("backend: " + ((typeof message === "string") ? message : JSON.stringify(message)));
    83 
    84         var messageObject = (typeof message === "string") ? JSON.parse(message) : message;
     156        let messageObject = (typeof message === "string") ? JSON.parse(message) : message;
    85157
    86158        if ("id" in messageObject)
     
    114186    // Private
    115187
     188    _startOrStopAutomaticTracing()
     189    {
     190        let setting = WebInspector.autoLogProtocolMessagesSetting;
     191
     192        // Bail if there is no state transition to be made.
     193        if (!(setting.value ^ !!this.activeTracer))
     194            return;
     195
     196        if (!setting.value) {
     197            if (this.activeTracer === this._automaticTracer)
     198                this.activeTracer = null;
     199
     200            this._automaticTracer = null;
     201        } else {
     202            this._automaticTracer = new WebInspector.LoggingProtocolTracer;
     203            this._automaticTracer.dumpMessagesToConsole = this.dumpInspectorProtocolMessages;
     204            this._automaticTracer.dumpTimingDataToConsole = this.dumpTimingDataToConsole;
     205            // This will be ignored if a custom tracer is installed.
     206            this.activeTracer = this._automaticTracer;
     207        }
     208    }
     209
    116210    _agentForDomain(domainName)
    117211    {
     
    138232        let responseData = {command, callback};
    139233
    140         if (this.dumpInspectorTimeStats)
     234        if (this.activeTracer)
    141235            responseData.sendRequestTimestamp = timestamp();
    142236
     
    159253        let responseData = {command};
    160254
    161         if (this.dumpInspectorTimeStats)
     255        if (this.activeTracer)
    162256            responseData.sendRequestTimestamp = timestamp();
    163257
     
    175269    {
    176270        let stringifiedMessage = JSON.stringify(messageObject);
    177         if (this.dumpInspectorProtocolMessages)
    178             this._log("frontend: " + stringifiedMessage);
     271        if (this.activeTracer)
     272            this.activeTracer.logFrontendRequest(stringifiedMessage);
    179273
    180274        InspectorFrontendHost.sendMessageToBackend(stringifiedMessage);
     
    196290        let {command, callback, promise} = responseData;
    197291
    198         var processingStartTimestamp;
    199         if (this.dumpInspectorTimeStats)
     292        let processingStartTimestamp;
     293        if (this.activeTracer) {
    200294            processingStartTimestamp = timestamp();
     295            this.activeTracer.logWillHandleResponse(JSON.stringify(messageObject));
     296        }
    201297
    202298        if (typeof callback === "function")
     
    207303            console.error("Received a command response without a corresponding callback or promise.", messageObject, command);
    208304
    209         let processingDuration = (timestamp() - processingStartTimestamp).toFixed(3);
    210         if (this.warnForLongMessageHandling && processingDuration > this.longMessageHandlingThreshold)
    211             console.warn(`InspectorBackend: took ${processingDuration}ms to handle response for command: ${command.qualifiedName}`);
    212 
    213         if (this.dumpInspectorTimeStats) {
    214             let roundTripDuration = (processingStartTimestamp - responseData.sendRequestTimestamp).toFixed(3);
    215             console.log(`time-stats: Handling: ${processingDuration}ms; RTT: ${roundTripDuration}ms; (command ${command.qualifiedName})`);
     305        if (this.activeTracer) {
     306            let processingTime = (timestamp() - processingStartTimestamp).toFixed(3);
     307            let roundTripTime = (processingStartTimestamp - responseData.sendRequestTimestamp).toFixed(3);
     308            this.activeTracer.logDidHandleResponse(JSON.stringify(messageObject), {rtt: roundTripTime, dispatch: processingTime});
    216309        }
    217310
     
    248341    _dispatchEvent(messageObject)
    249342    {
    250         var qualifiedName = messageObject["method"];
    251         var [domainName, eventName] = qualifiedName.split(".");
     343        let qualifiedName = messageObject["method"];
     344        let [domainName, eventName] = qualifiedName.split(".");
    252345        if (!(domainName in this._agents)) {
    253346            console.error("Protocol Error: Attempted to dispatch method '" + eventName + "' for non-existing domain '" + domainName + "'");
     
    255348        }
    256349
    257         var agent = this._agentForDomain(domainName);
     350        let agent = this._agentForDomain(domainName);
    258351        if (!agent.active) {
    259352            console.error("Protocol Error: Attempted to dispatch method for domain '" + domainName + "' which exists but is not active.");
     
    261354        }
    262355
    263         var event = agent.getEvent(eventName);
     356        let event = agent.getEvent(eventName);
    264357        if (!event) {
    265358            console.error("Protocol Error: Attempted to dispatch an unspecified method '" + qualifiedName + "'");
     
    267360        }
    268361
    269         var eventArguments = [];
    270         if (messageObject["params"]) {
    271             var parameterNames = event.parameterNames;
    272             for (var i = 0; i < parameterNames.length; ++i)
    273                 eventArguments.push(messageObject["params"][parameterNames[i]]);
    274         }
    275 
    276         var processingStartTimestamp;
    277         if (this.dumpInspectorTimeStats)
     362        let eventArguments = [];
     363        if (messageObject["params"])
     364            eventArguments = event.parameterNames.map((name) => messageObject["params"][name]);
     365
     366        let processingStartTimestamp;
     367        if (this.activeTracer) {
    278368            processingStartTimestamp = timestamp();
     369            this.activeTracer.logWillHandleEvent(JSON.stringify(messageObject));
     370        }
    279371
    280372        try {
     
    282374        } catch (e) {
    283375            console.error("Uncaught exception in inspector page while handling event " + qualifiedName, e);
    284         }
    285 
    286         let processingDuration = (timestamp() - processingStartTimestamp).toFixed(3);
    287         if (this.warnForLongMessageHandling && processingDuration > this.longMessageHandlingThreshold)
    288             console.warn(`InspectorBackend: took ${processingDuration}ms to handle event: ${messageObject.method}`);
    289 
    290         if (this.dumpInspectorTimeStats)
    291             console.log(`time-stats: Handling: ${processingDuration}ms (event ${messageObject.method})`);
     376            if (this.activeTracer)
     377                this.activeTracer.logFrontendException(JSON.stringify(messageObject), e);
     378        }
     379
     380        if (this.activeTracer) {
     381            let processingTime = (timestamp() - processingStartTimestamp).toFixed(3);
     382            this.activeTracer.logDidHandleEvent(JSON.stringify(messageObject), {dispatch: processingTime});
     383        }
    292384    }
    293385
     
    301393        console.assert(this._pendingResponses.size === 0);
    302394
    303         var scriptsToRun = this._deferredScripts;
     395        let scriptsToRun = this._deferredScripts;
    304396        this._deferredScripts = [];
    305         for (var script of scriptsToRun)
     397        for (let script of scriptsToRun)
    306398            script.call(this);
    307399    }
  • trunk/Source/WebInspectorUI/UserInterface/Test.html

    r192906 r193870  
    5050    <script src="Base/URLUtilities.js"></script>
    5151    <script src="Base/Utilities.js"></script>
     52    <script src="Base/Setting.js"></script>
     53
     54    <script src="Protocol/ProtocolTracer.js"></script>
     55    <script src="Protocol/LoggingProtocolTracer.js"></script>
    5256
    5357    <script src="Protocol/InspectorBackend.js"></script>
     
    136140    <script src="Models/ScriptSyntaxTree.js"></script>
    137141    <script src="Models/ScriptTimelineRecord.js"></script>
    138     <script src="Models/Setting.js"></script>
    139142    <script src="Models/SourceCodeLocation.js"></script>
    140143    <script src="Models/SourceCodeRevision.js"></script>
Note: See TracChangeset for help on using the changeset viewer.