Changeset 194546 in webkit
- Timestamp:
- Jan 4, 2016 12:37:10 PM (8 years ago)
- Location:
- trunk/Source/WebInspectorUI
- Files:
-
- 1 added
- 6 edited
- 1 copied
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/WebInspectorUI/ChangeLog
r194539 r194546 1 2016-01-04 Brian Burg <bburg@apple.com> 2 3 Web Inspector: add a DebugUI context menu item for saving inspector protocol traffic to file 4 https://bugs.webkit.org/show_bug.cgi?id=152671 5 6 Reviewed by Timothy Hatcher. 7 8 Add a new tracer that captures all messages, and debug context menu 9 items to control whether to capture protocol traffic and export it. 10 In later patches, a reciprocal "Import..." context menu item will 11 allow opening saved protocol traces and viewing them in a debug UI 12 content view for debugging/visualizing protocol traffic. 13 14 * UserInterface/Base/Main.js: 15 * UserInterface/Debug/CapturingProtocolTracer.js: Copied from Source/WebInspectorUI/UserInterface/Protocol/ProtocolTracer.js. 16 17 This tracer saves everything into a flat array. JSON protocol 18 messages are saved as escaped strings, in case they are not 19 valid JSON. We want to be able to debug such scenarios. 20 21 (WebInspector.CapturingProtocolTracer): 22 (WebInspector.CapturingProtocolTracer.prototype.get trace): 23 (WebInspector.CapturingProtocolTracer.prototype.logFrontendException): 24 (WebInspector.CapturingProtocolTracer.prototype.logProtocolError): 25 (WebInspector.CapturingProtocolTracer.prototype.logFrontendRequest): 26 (WebInspector.CapturingProtocolTracer.prototype.logDidHandleResponse): 27 (WebInspector.CapturingProtocolTracer.prototype.logDidHandleEvent): 28 (WebInspector.CapturingProtocolTracer.prototype._stringifyMessage): 29 (WebInspector.CapturingProtocolTracer.prototype._processEntry): 30 31 * UserInterface/Debug/ProtocolTrace.js: Added. 32 33 This is a dumb container that holds protocol trace data. It will 34 be responsible for deserializing saved trace files in later work. 35 36 (WebInspector.ProtocolTrace): 37 (WebInspector.ProtocolTrace.prototype.addEntry): 38 (WebInspector.ProtocolTrace.prototype.get saveData): 39 * UserInterface/Main.html: 40 * UserInterface/Protocol/InspectorBackend.js: 41 (InspectorBackendClass): 42 43 Simplify the implementation. Now there are one or two tracers 44 at any given time. The default tracer handles legacy logging 45 behavior and always exists. The custom tracer is installed when 46 the "Capture Protocol Traffic" context menu item is toggled. 47 48 Dispatch to the array of active tracers at each trace point. 49 Tracers now get the actual JSON message instead of a stringified 50 version passed as an argument. 51 52 (InspectorBackendClass.prototype.set dumpInspectorProtocolMessages): 53 (InspectorBackendClass.prototype.get dumpInspectorProtocolMessages): 54 (InspectorBackendClass.prototype.set dumpInspectorTimeStats): 55 (InspectorBackendClass.prototype.set customTracer): 56 (InspectorBackendClass.prototype.get activeTracers): 57 (InspectorBackendClass.prototype._startOrStopAutomaticTracing): 58 (InspectorBackendClass.prototype._sendMessageToBackend): 59 (InspectorBackendClass.prototype._dispatchResponse): 60 (InspectorBackendClass.prototype._dispatchEvent): 61 (InspectorBackendClass.prototype.set activeTracer): Deleted. 62 (InspectorBackendClass.prototype.get activeTracer): Deleted. 63 * UserInterface/Protocol/LoggingProtocolTracer.js: 64 (WebInspector.LoggingProtocolTracer.prototype._processEntry): 65 (WebInspector.LoggingProtocolTracer): 66 (WebInspector.LoggingProtocolTracer.prototype.logFrontendRequest): 67 (WebInspector.LoggingProtocolTracer.prototype.logWillHandleResponse): 68 (WebInspector.LoggingProtocolTracer.prototype.logDidHandleResponse): 69 (WebInspector.LoggingProtocolTracer.prototype.logWillHandleEvent): 70 (WebInspector.LoggingProtocolTracer.prototype.logDidHandleEvent): 71 * UserInterface/Protocol/ProtocolTracer.js: 72 (WebInspector.ProtocolTracer.prototype.logFrontendException): 73 (WebInspector.ProtocolTracer.prototype.logProtocolError): 74 (WebInspector.ProtocolTracer.prototype.logFrontendRequest): 75 (WebInspector.ProtocolTracer.prototype.logWillHandleResponse): 76 (WebInspector.ProtocolTracer.prototype.logDidHandleResponse): 77 (WebInspector.ProtocolTracer.prototype.logWillHandleEvent): 78 (WebInspector.ProtocolTracer.prototype.logDidHandleEvent): 79 1 80 2016-01-04 Devin Rousso <dcrousso+webkit@gmail.com> 2 81 -
trunk/Source/WebInspectorUI/UserInterface/Base/Main.js
r194506 r194546 1 1 /* 2 * Copyright (C) 2013-201 4Apple Inc. All rights reserved.2 * Copyright (C) 2013-2016 Apple Inc. All rights reserved. 3 3 * 4 4 * Redistribution and use in source and binary forms, with or without … … 1379 1379 window.location.reload(); 1380 1380 }); 1381 1382 let protocolSubMenu = proposedContextMenu.appendSubMenuItem(WebInspector.unlocalizedString("Protocol Debugging"), null, false); 1383 let isCapturingTraffic = InspectorBackend.activeTracer instanceof WebInspector.CapturingProtocolTracer; 1384 1385 protocolSubMenu.appendCheckboxItem(WebInspector.unlocalizedString("Capture Trace"), () => { 1386 if (isCapturingTraffic) 1387 InspectorBackend.activeTracer = null; 1388 else 1389 InspectorBackend.activeTracer = new WebInspector.CapturingProtocolTracer; 1390 }, isCapturingTraffic); 1391 1392 protocolSubMenu.appendSeparator(); 1393 1394 protocolSubMenu.appendItem(WebInspector.unlocalizedString("Export Trace\u2014"), () => { 1395 const forceSaveAs = true; 1396 WebInspector.saveDataToFile(InspectorBackend.activeTracer.trace.saveData, forceSaveAs); 1397 }, !isCapturingTraffic); 1381 1398 } else { 1382 1399 const onlyExisting = true; -
trunk/Source/WebInspectorUI/UserInterface/Debug/CapturingProtocolTracer.js
r194545 r194546 1 1 /* 2 * Copyright (C) 201 5Apple Inc. All rights reserved.2 * Copyright (C) 2016 Apple Inc. All rights reserved. 3 3 * 4 4 * Redistribution and use in source and binary forms, with or without … … 24 24 */ 25 25 26 WebInspector. ProtocolTracer = class ProtocolTracer extends WebInspector.Object26 WebInspector.CapturingProtocolTracer = class CapturingProtocolTracer extends WebInspector.ProtocolTracer 27 27 { 28 constructor() 29 { 30 super(); 31 32 this._trace = new WebInspector.ProtocolTrace; 33 } 34 28 35 // Public 29 36 30 logStarted()37 get trace() 31 38 { 32 // To be overridden by subclasses.39 return this._trace; 33 40 } 34 41 35 42 logFrontendException(message, exception) 36 43 { 37 console.assert(typeof message === "string", "Must stringify messages to avoid leaking all JSON protocol messages.") 38 39 // To be overridden by subclasses. 44 this._processEntry({type: "exception", message: this._stringifyMessage(message), exception}); 40 45 } 41 46 42 47 logProtocolError(message, error) 43 48 { 44 console.assert(typeof message === "string", "Must stringify messages to avoid leaking all JSON protocol messages.") 45 46 // To be overridden by subclasses. 49 this._processEntry({type: "error", message: this._stringifyMessage(message), error}); 47 50 } 48 51 49 52 logFrontendRequest(message) 50 53 { 51 console.assert(typeof message === "string", "Must stringify messages to avoid leaking all JSON protocol messages.") 52 53 // To be overridden by subclasses. 54 } 55 56 logWillHandleResponse(message) 57 { 58 console.assert(typeof message === "string", "Must stringify messages to avoid leaking all JSON protocol messages.") 59 60 // To be overridden by subclasses. 54 this._processEntry({type: "request", message: this._stringifyMessage(message)}); 61 55 } 62 56 63 57 logDidHandleResponse(message, timings = null) 64 58 { 65 console.assert(typeof message === "string", "Must stringify messages to avoid leaking all JSON protocol messages.") 59 let entry = {type: "response", message: this._stringifyMessage(message)}; 60 if (timings) 61 entry.timings = Object.shallowCopy(timings); 66 62 67 // To be overridden by subclasses. 68 } 69 70 logWillHandleEvent(message) 71 { 72 console.assert(typeof message === "string", "Must stringify messages to avoid leaking all JSON protocol messages.") 73 74 // To be overridden by subclasses. 63 this._processEntry(entry); 75 64 } 76 65 77 66 logDidHandleEvent(message, timings = null) 78 67 { 79 console.assert(typeof message === "string", "Must stringify messages to avoid leaking all JSON protocol messages.") 68 let entry = {type: "event", message: this._stringifyMessage(message)}; 69 if (timings) 70 entry.timings = Object.shallowCopy(timings); 80 71 81 // To be overridden by subclasses.72 this._processEntry(entry); 82 73 } 83 74 84 logFinished()75 _stringifyMessage(message) 85 76 { 86 // To be overridden by subclasses. 77 try { 78 return JSON.stringify(message); 79 } catch (e) { 80 console.error("couldn't stringify object:", message, e); 81 return {}; 82 } 83 } 84 85 _processEntry(entry) 86 { 87 this._trace.addEntry(entry); 87 88 } 88 89 }; -
trunk/Source/WebInspectorUI/UserInterface/Main.html
r194504 r194546 644 644 645 645 <script src="Debug/Bootstrap.js"></script> 646 <script src="Debug/CapturingProtocolTracer.js"></script> 647 <script src="Debug/ProtocolTrace.js"></script> 646 648 647 649 <script> -
trunk/Source/WebInspectorUI/UserInterface/Protocol/InspectorBackend.js
r193870 r194546 1 1 /* 2 2 * Copyright (C) 2011 Google Inc. All rights reserved. 3 * Copyright (C) 2013, 2015 Apple Inc. All rights reserved.3 * Copyright (C) 2013, 2015, 2016 Apple Inc. All rights reserved. 4 4 * Copyright (C) 2014 University of Washington. 5 5 * … … 39 39 this._agents = {}; 40 40 this._deferredScripts = []; 41 this._activeTracer = null; 42 this._automaticTracer = null; 41 42 this._customTracer = null; 43 this._defaultTracer = new WebInspector.LoggingProtocolTracer; 44 this._activeTracers = [this._defaultTracer]; 43 45 44 46 this._dumpInspectorTimeStats = false; … … 60 62 setting.value = value; 61 63 62 if (this.activeTracer !== this._automaticTracer) 63 return; 64 65 if (this.activeTracer) 66 this.activeTracer.dumpMessagesToConsole = value; 64 this._defaultTracer.dumpMessagesToConsole = value; 67 65 } 68 66 69 67 get dumpInspectorProtocolMessages() 70 68 { 71 return !!this._automaticTracer;69 return WebInspector.autoLogProtocolMessagesSetting.value; 72 70 } 73 71 … … 77 75 this.dumpInspectorProtocolMessages = true; 78 76 79 if (this.activeTracer !== this._automaticTracer) 77 this._defaultTracer.dumpTimingDataToConsole = value; 78 } 79 80 get dumpInspectorTimeStats() 81 { 82 return this._dumpInspectorTimeStats; 83 } 84 85 set customTracer(tracer) 86 { 87 console.assert(!tracer || tracer instanceof WebInspector.ProtocolTracer, tracer); 88 console.assert(!tracer || tracer !== this._defaultTracer, tracer); 89 90 // Bail early if no state change is to be made. 91 if (!tracer && !this._customTracer) 80 92 return; 81 93 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) 94 if (tracer === this._customTracer) 97 95 return; 98 96 99 if (tracer === this._ activeTracer)97 if (tracer === this._defaultTracer) 100 98 return; 101 99 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; 100 if (this._customTracer) 101 this._customTracer.logFinished(); 102 103 this._customTracer = tracer; 104 this._activeTracers = [this._defaultTracer]; 105 106 if (this._customTracer) { 107 this._customTracer.logStarted(); 108 this._activeTracers.push(this._customTracer); 109 } 110 } 111 112 get activeTracers() 113 { 114 return this._activeTracers; 125 115 } 126 116 … … 188 178 _startOrStopAutomaticTracing() 189 179 { 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 } 180 this._defaultTracer.dumpMessagesToConsole = this.dumpInspectorProtocolMessages; 181 this._defaultTracer.dumpTimingDataToConsole = this.dumpTimingDataToConsole; 208 182 } 209 183 … … 268 242 _sendMessageToBackend(messageObject) 269 243 { 270 let stringifiedMessage = JSON.stringify(messageObject); 271 if (this.activeTracer) 272 this.activeTracer.logFrontendRequest(stringifiedMessage); 273 274 InspectorFrontendHost.sendMessageToBackend(stringifiedMessage); 244 for (let tracer of this.activeTracers) 245 tracer.logFrontendRequest(messageObject); 246 247 InspectorFrontendHost.sendMessageToBackend(JSON.stringify(messageObject)); 275 248 } 276 249 … … 287 260 console.assert(this._pendingResponses.has(sequenceId), sequenceId, this._pendingResponses); 288 261 289 let responseData = this._pendingResponses.take(sequenceId) ;262 let responseData = this._pendingResponses.take(sequenceId) || {}; 290 263 let {command, callback, promise} = responseData; 291 264 292 let processingStartTimestamp; 293 if (this.activeTracer) { 294 processingStartTimestamp = timestamp(); 295 this.activeTracer.logWillHandleResponse(JSON.stringify(messageObject)); 296 } 265 let processingStartTimestamp = timestamp(); 266 for (let tracer of this.activeTracers) 267 tracer.logWillHandleResponse(messageObject); 297 268 298 269 if (typeof callback === "function") … … 303 274 console.error("Received a command response without a corresponding callback or promise.", messageObject, command); 304 275 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});309 }276 let processingTime = (timestamp() - processingStartTimestamp).toFixed(3); 277 let roundTripTime = (processingStartTimestamp - responseData.sendRequestTimestamp).toFixed(3); 278 279 for (let tracer of this.activeTracers) 280 tracer.logDidHandleResponse(messageObject, {rtt: roundTripTime, dispatch: processingTime}); 310 281 311 282 if (this._deferredScripts.length && !this._pendingResponses.size) … … 364 335 eventArguments = event.parameterNames.map((name) => messageObject["params"][name]); 365 336 366 let processingStartTimestamp; 367 if (this.activeTracer) { 368 processingStartTimestamp = timestamp(); 369 this.activeTracer.logWillHandleEvent(JSON.stringify(messageObject)); 370 } 337 let processingStartTimestamp = timestamp(); 338 for (let tracer of this.activeTracers) 339 tracer.logWillHandleEvent(messageObject); 371 340 372 341 try { … … 374 343 } catch (e) { 375 344 console.error("Uncaught exception in inspector page while handling event " + qualifiedName, e); 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 } 345 for (let tracer of this.activeTracers) 346 tracer.logFrontendException(messageObject, e); 347 } 348 349 let processingDuration = (timestamp() - processingStartTimestamp).toFixed(3); 350 for (let tracer of this.activeTracers) 351 tracer.logDidHandleEvent(messageObject, {dispatch: processingDuration}); 384 352 } 385 353 -
trunk/Source/WebInspectorUI/UserInterface/Protocol/LoggingProtocolTracer.js
r194244 r194546 1 1 /* 2 * Copyright (C) 2015 Apple Inc. All rights reserved.2 * Copyright (C) 2015, 2016 Apple Inc. All rights reserved. 3 3 * 4 4 * Redistribution and use in source and binary forms, with or without … … 69 69 logFrontendRequest(message) 70 70 { 71 console.assert(typeof message === "string", "Must stringify messages to avoid leaking all JSON protocol messages.")72 73 71 this._processEntry({type: "request", message}); 74 72 } … … 76 74 logWillHandleResponse(message) 77 75 { 78 console.assert(typeof message === "string", "Must stringify messages to avoid leaking all JSON protocol messages.")79 80 76 let entry = {type: "response", message}; 81 77 this._processEntry(entry); … … 84 80 logDidHandleResponse(message, timings = null) 85 81 { 86 console.assert(typeof message === "string", "Must stringify messages to avoid leaking all JSON protocol messages.")87 88 82 let entry = {type: "response", message}; 89 83 if (timings) … … 95 89 logWillHandleEvent(message) 96 90 { 97 console.assert(typeof message === "string", "Must stringify messages to avoid leaking all JSON protocol messages.")98 99 91 let entry = {type: "event", message}; 100 92 this._processEntry(entry); … … 103 95 logDidHandleEvent(message, timings = null) 104 96 { 105 console.assert(typeof message === "string", "Must stringify messages to avoid leaking all JSON protocol messages.")106 107 97 let entry = {type: "event", message}; 108 98 if (timings) … … 120 110 this._logToConsole(`time-stats: Handling: ${entry.timings.dispatch || NaN}ms`); 121 111 } else if (this._dumpMessagesToConsole && !entry.timings) 122 this._logToConsole(`${entry.type}: ${ entry.message}`);112 this._logToConsole(`${entry.type}: ${JSON.stringify(entry.message)}`); 123 113 } 124 114 }; -
trunk/Source/WebInspectorUI/UserInterface/Protocol/ProtocolTracer.js
r193870 r194546 1 1 /* 2 * Copyright (C) 2015 Apple Inc. All rights reserved.2 * Copyright (C) 2015, 2016 Apple Inc. All rights reserved. 3 3 * 4 4 * Redistribution and use in source and binary forms, with or without … … 35 35 logFrontendException(message, exception) 36 36 { 37 console.assert(typeof message === "string", "Must stringify messages to avoid leaking all JSON protocol messages.")38 39 37 // To be overridden by subclasses. 40 38 } … … 42 40 logProtocolError(message, error) 43 41 { 44 console.assert(typeof message === "string", "Must stringify messages to avoid leaking all JSON protocol messages.")45 46 42 // To be overridden by subclasses. 47 43 } … … 49 45 logFrontendRequest(message) 50 46 { 51 console.assert(typeof message === "string", "Must stringify messages to avoid leaking all JSON protocol messages.")52 53 47 // To be overridden by subclasses. 54 48 } … … 56 50 logWillHandleResponse(message) 57 51 { 58 console.assert(typeof message === "string", "Must stringify messages to avoid leaking all JSON protocol messages.")59 60 52 // To be overridden by subclasses. 61 53 } … … 63 55 logDidHandleResponse(message, timings = null) 64 56 { 65 console.assert(typeof message === "string", "Must stringify messages to avoid leaking all JSON protocol messages.")66 67 57 // To be overridden by subclasses. 68 58 } … … 70 60 logWillHandleEvent(message) 71 61 { 72 console.assert(typeof message === "string", "Must stringify messages to avoid leaking all JSON protocol messages.")73 74 62 // To be overridden by subclasses. 75 63 } … … 77 65 logDidHandleEvent(message, timings = null) 78 66 { 79 console.assert(typeof message === "string", "Must stringify messages to avoid leaking all JSON protocol messages.")80 81 67 // To be overridden by subclasses. 82 68 }
Note: See TracChangeset
for help on using the changeset viewer.