Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(608)

Side by Side Diff: chrome/browser/resources/net_internals/main.js

Issue 6025017: Adds the ability to load JSON log files to about:net-internals. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: Put load log button on its own line Created 9 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 /** 5 /**
6 * Dictionary of constants (initialized by browser). 6 * Dictionary of constants (initialized by browser).
7 */ 7 */
8 var LogEventType = null; 8 var LogEventType = null;
9 var LogEventPhase = null; 9 var LogEventPhase = null;
10 var ClientInfo = null; 10 var ClientInfo = null;
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after
68 'hostResolverIPv6Disabled', 68 'hostResolverIPv6Disabled',
69 'hostResolverEnableIPv6', 69 'hostResolverEnableIPv6',
70 'hostResolverCacheCapacity', 70 'hostResolverCacheCapacity',
71 'hostResolverCacheTTLSuccess', 71 'hostResolverCacheTTLSuccess',
72 'hostResolverCacheTTLFailure'); 72 'hostResolverCacheTTLFailure');
73 73
74 // Create a view which will display import/export options to control the 74 // Create a view which will display import/export options to control the
75 // captured data. 75 // captured data.
76 var dataView = new DataView('dataTabContent', 'exportedDataText', 76 var dataView = new DataView('dataTabContent', 'exportedDataText',
77 'exportToText', 'securityStrippingCheckbox', 77 'exportToText', 'securityStrippingCheckbox',
78 'byteLoggingCheckbox', 78 'byteLoggingCheckbox', 'passivelyCapturedCount',
79 'passivelyCapturedCount', 79 'activelyCapturedCount', 'dataViewDeleteAll',
80 'activelyCapturedCount', 80 'dataViewDumpDataDiv', 'dataViewLoadDataDiv',
81 'dataViewDeleteAll'); 81 'dataViewLoadLogFile',
82 'dataViewCapturingTextSpan',
83 'dataViewLoggingTextSpan');
82 84
83 // Create a view which will display the results and controls for connection 85 // Create a view which will display the results and controls for connection
84 // tests. 86 // tests.
85 var testView = new TestView('testTabContent', 'testUrlInput', 87 var testView = new TestView('testTabContent', 'testUrlInput',
86 'connectionTestsForm', 'testSummary'); 88 'connectionTestsForm', 'testSummary');
87 89
88 var httpCacheView = new HttpCacheView('httpCacheTabContent', 90 var httpCacheView = new HttpCacheView('httpCacheTabContent',
89 'httpCacheStats'); 91 'httpCacheStats');
90 92
91 var socketsView = new SocketsView('socketsTabContent', 93 var socketsView = new SocketsView('socketsTabContent',
92 'socketPoolDiv', 94 'socketPoolDiv',
93 'socketPoolGroupsDiv'); 95 'socketPoolGroupsDiv');
94 96
95 var spdyView = new SpdyView('spdyTabContent', 97 var spdyView = new SpdyView('spdyTabContent',
96 'spdySessionNoneSpan', 98 'spdySessionNoneSpan',
97 'spdySessionLinkSpan', 99 'spdySessionLinkSpan',
98 'spdySessionDiv'); 100 'spdySessionDiv');
99 101
100 102
101 var serviceView; 103 var serviceView;
102 if (g_browser.isPlatformWindows()) { 104 if (g_browser.isPlatformWindows()) {
103 serviceView = new ServiceProvidersView('serviceProvidersTab', 105 serviceView = new ServiceProvidersView('serviceProvidersTab',
104 'serviceProvidersTabContent', 106 'serviceProvidersTabContent',
105 'serviceProvidersTbody', 107 'serviceProvidersTbody',
106 'namespaceProvidersTbody'); 108 'namespaceProvidersTbody');
107 } 109 }
108 110
109 // Create a view which lets you tab between the different sub-views. 111 // Create a view which lets you tab between the different sub-views.
110 var categoryTabSwitcher = new TabSwitcherView('categoryTabHandles'); 112 var categoryTabSwitcher = new TabSwitcherView('categoryTabHandles');
113 g_browser.setTabSwitcher(categoryTabSwitcher);
111 114
112 // Populate the main tabs. 115 // Populate the main tabs.
113 categoryTabSwitcher.addTab('eventsTab', eventsView, false); 116 categoryTabSwitcher.addTab('eventsTab', eventsView, false);
114 categoryTabSwitcher.addTab('proxyTab', proxyView, false); 117 categoryTabSwitcher.addTab('proxyTab', proxyView, false);
115 categoryTabSwitcher.addTab('dnsTab', dnsView, false); 118 categoryTabSwitcher.addTab('dnsTab', dnsView, false);
116 categoryTabSwitcher.addTab('socketsTab', socketsView, false); 119 categoryTabSwitcher.addTab('socketsTab', socketsView, false);
117 categoryTabSwitcher.addTab('spdyTab', spdyView, false); 120 categoryTabSwitcher.addTab('spdyTab', spdyView, false);
118 categoryTabSwitcher.addTab('httpCacheTab', httpCacheView, false); 121 categoryTabSwitcher.addTab('httpCacheTab', httpCacheView, false);
119 categoryTabSwitcher.addTab('dataTab', dataView, false); 122 categoryTabSwitcher.addTab('dataTab', dataView, false);
120 if (g_browser.isPlatformWindows()) 123 if (g_browser.isPlatformWindows())
(...skipping 16 matching lines...) Expand all
137 140
138 // Make this category tab widget the primary view, that fills the whole page. 141 // Make this category tab widget the primary view, that fills the whole page.
139 var windowView = new WindowView(categoryTabSwitcher); 142 var windowView = new WindowView(categoryTabSwitcher);
140 143
141 // Trigger initial layout. 144 // Trigger initial layout.
142 windowView.resetGeometry(); 145 windowView.resetGeometry();
143 146
144 // Select the initial view based on the current URL. 147 // Select the initial view based on the current URL.
145 window.onhashchange(); 148 window.onhashchange();
146 149
150 // Inform observers a log file is not currently being displayed.
151 g_browser.setIsViewingLogFile_(false);
152
147 // Tell the browser that we are ready to start receiving log events. 153 // Tell the browser that we are ready to start receiving log events.
148 g_browser.sendReady(); 154 g_browser.sendReady();
149 } 155 }
150 156
151 /** 157 /**
152 * This class provides a "bridge" for communicating between the javascript and 158 * This class provides a "bridge" for communicating between the javascript and
153 * the browser. 159 * the browser.
154 * 160 *
155 * @constructor 161 * @constructor
156 */ 162 */
(...skipping 27 matching lines...) Expand all
184 this.sendGetServiceProviders.bind(this)); 190 this.sendGetServiceProviders.bind(this));
185 } 191 }
186 192
187 // Cache of the data received. 193 // Cache of the data received.
188 this.numPassivelyCapturedEvents_ = 0; 194 this.numPassivelyCapturedEvents_ = 0;
189 this.capturedEvents_ = []; 195 this.capturedEvents_ = [];
190 196
191 // Next unique id to be assigned to a log entry without a source. 197 // Next unique id to be assigned to a log entry without a source.
192 // Needed to simplify deletion, identify associated GUI elements, etc. 198 // Needed to simplify deletion, identify associated GUI elements, etc.
193 this.nextSourcelessEventId_ = -1; 199 this.nextSourcelessEventId_ = -1;
200
201 // True when viewing a log file rather than actively logged events.
202 // When viewing a log file, all tabs are hidden except the event view,
203 // and all received events are ignored.
204 this.isViewingLogFile_ = false;
194 } 205 }
195 206
196 /* 207 /*
197 * Takes the current hash in form of "#tab&param1=value1&param2=value2&...". 208 * Takes the current hash in form of "#tab&param1=value1&param2=value2&...".
198 * Puts the parameters in an object, and passes the resulting object to 209 * Puts the parameters in an object, and passes the resulting object to
199 * |categoryTabSwitcher|. Uses tab and |anchorMap| to find a tab ID, 210 * |categoryTabSwitcher|. Uses tab and |anchorMap| to find a tab ID,
200 * which it also passes to the tab switcher. 211 * which it also passes to the tab switcher.
201 * 212 *
202 * Parameters and values are decoded with decodeURIComponent(). 213 * Parameters and values are decoded with decodeURIComponent().
203 */ 214 */
(...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after
295 }; 306 };
296 307
297 BrowserBridge.prototype.enableIPv6 = function() { 308 BrowserBridge.prototype.enableIPv6 = function() {
298 chrome.send('enableIPv6'); 309 chrome.send('enableIPv6');
299 }; 310 };
300 311
301 BrowserBridge.prototype.setLogLevel = function(logLevel) { 312 BrowserBridge.prototype.setLogLevel = function(logLevel) {
302 chrome.send('setLogLevel', ['' + logLevel]); 313 chrome.send('setLogLevel', ['' + logLevel]);
303 } 314 }
304 315
316 BrowserBridge.prototype.loadLogFile = function() {
317 chrome.send('loadLogFile');
318 }
319
305 //------------------------------------------------------------------------------ 320 //------------------------------------------------------------------------------
306 // Messages received from the browser 321 // Messages received from the browser
307 //------------------------------------------------------------------------------ 322 //------------------------------------------------------------------------------
308 323
309 BrowserBridge.prototype.receivedLogEntries = function(logEntries) { 324 BrowserBridge.prototype.receivedLogEntries = function(logEntries) {
310 for (var e = 0; e < logEntries.length; ++e) { 325 // Does nothing if viewing a log file.
311 var logEntry = logEntries[e]; 326 if (this.isViewingLogFile_)
312 327 return;
313 // Assign unique ID, if needed. 328 this.addLogEntries(logEntries);
314 if (logEntry.source.id == 0) {
315 logEntry.source.id = this.nextSourcelessEventId_;
316 --this.nextSourcelessEventId_;
317 }
318 this.capturedEvents_.push(logEntry);
319 for (var i = 0; i < this.logObservers_.length; ++i)
320 this.logObservers_[i].onLogEntryAdded(logEntry);
321 }
322 }; 329 };
323 330
324 BrowserBridge.prototype.receivedLogEventTypeConstants = function(constantsMap) { 331 BrowserBridge.prototype.receivedLogEventTypeConstants = function(constantsMap) {
325 LogEventType = constantsMap; 332 LogEventType = constantsMap;
326 }; 333 };
327 334
328 BrowserBridge.prototype.receivedClientInfo = 335 BrowserBridge.prototype.receivedClientInfo =
329 function(info) { 336 function(info) {
330 ClientInfo = info; 337 ClientInfo = info;
331 }; 338 };
(...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after
432 439
433 BrowserBridge.prototype.receivedCompletedConnectionTestSuite = function() { 440 BrowserBridge.prototype.receivedCompletedConnectionTestSuite = function() {
434 for (var i = 0; i < this.connectionTestsObservers_.length; ++i) 441 for (var i = 0; i < this.connectionTestsObservers_.length; ++i)
435 this.connectionTestsObservers_[i].onCompletedConnectionTestSuite(); 442 this.connectionTestsObservers_[i].onCompletedConnectionTestSuite();
436 }; 443 };
437 444
438 BrowserBridge.prototype.receivedHttpCacheInfo = function(info) { 445 BrowserBridge.prototype.receivedHttpCacheInfo = function(info) {
439 this.pollableDataHelpers_.httpCacheInfo.update(info); 446 this.pollableDataHelpers_.httpCacheInfo.update(info);
440 }; 447 };
441 448
449 BrowserBridge.prototype.loadedLogFile = function(logFileContents) {
450 var match;
451 // Replace carriage returns with linebreaks and then split around linebreaks.
452 var lines = logFileContents.replace(/\r/g, '\n').split('\n');
453 var entries = [];
454 var numInvalidLines = 0;
455
456 for (var i = 0; i < lines.length; ++i) {
457 if (lines[i].trim().length == 0)
458 continue;
459 // Parse all valid lines, skipping any others.
460 try {
461 var entry = JSON.parse(lines[i]);
462 if (entry &&
463 typeof(entry) == 'object' &&
464 entry.phase != undefined &&
465 entry.source != undefined &&
466 entry.time != undefined &&
467 entry.type != undefined) {
468 entries.push(entry);
469 continue;
470 }
471 } catch (err) {
472 }
473 ++numInvalidLines;
474 console.log('Unable to parse log line: ' + lines[i]);
475 }
476
477 if (entries.length == 0) {
478 window.alert('Loading log file failed.');
479 return;
480 }
481
482 this.deleteAllEvents();
483
484 this.setIsViewingLogFile_(true);
485
486 var validEntries = [];
487 for (var i = 0; i < entries.length; ++i) {
488 entries[i].wasPassivelyCaptured = true;
489 if (LogEventType[entries[i].type] != undefined &&
490 LogSourceType[entries[i].source.type] != undefined &&
491 LogEventPhase[entries[i].phase] != undefined) {
492 entries[i].type = LogEventType[entries[i].type];
493 entries[i].source.type = LogSourceType[entries[i].source.type];
494 entries[i].phase = LogEventPhase[entries[i].phase];
495 validEntries.push(entries[i]);
496 } else {
497 // TODO(mmenke): Do something reasonable when the event type isn't
498 // found, which could happen when event types are
499 // removed or added between versions. Could also happen
500 // with source types, but less likely.
501 console.log(
502 'Unrecognized values in log entry: ' + JSON.stringify(entry));
503 }
504 }
505
506 this.numPassivelyCapturedEvents_ = validEntries.length;
507 this.addLogEntries(validEntries);
508
509 var numInvalidEntries = entries.length - validEntries.length;
510 if (numInvalidEntries > 0 || numInvalidLines > 0) {
511 window.alert(
512 numInvalidLines.toString() +
513 ' could not be parsed as JSON strings, and ' +
514 numInvalidEntries.toString() +
515 ' entries don\'t have valid data.\n\n' +
516 'Unparseable lines may indicate log file corruption.\n' +
517 'Entries with invalid data may be caused by version differences.\n\n' +
518 'See console for more information.');
519 }
520 }
521
442 //------------------------------------------------------------------------------ 522 //------------------------------------------------------------------------------
443 523
444 /** 524 /**
525 * Sets the |categoryTabSwitcher_| of BrowserBridge. Since views depend on
526 * g_browser being initialized, have to have a BrowserBridge prior to tab
527 * construction.
528 */
529 BrowserBridge.prototype.setTabSwitcher = function(categoryTabSwitcher) {
530 this.categoryTabSwitcher_ = categoryTabSwitcher;
531 };
532
533 /**
445 * Adds a listener of log entries. |observer| will be called back when new log 534 * Adds a listener of log entries. |observer| will be called back when new log
446 * data arrives, through: 535 * data arrives, through:
447 * 536 *
448 * observer.onLogEntryAdded(logEntry) 537 * observer.onLogEntryAdded(logEntry)
449 */ 538 */
450 BrowserBridge.prototype.addLogObserver = function(observer) { 539 BrowserBridge.prototype.addLogObserver = function(observer) {
451 this.logObservers_.push(observer); 540 this.logObservers_.push(observer);
452 }; 541 };
453 542
454 /** 543 /**
(...skipping 130 matching lines...) Expand 10 before | Expand all | Expand 10 after
585 674
586 /** 675 /**
587 * Returns the number of events that were captured passively by the 676 * Returns the number of events that were captured passively by the
588 * browser prior to when the net-internals page was started. 677 * browser prior to when the net-internals page was started.
589 */ 678 */
590 BrowserBridge.prototype.getNumPassivelyCapturedEvents = function() { 679 BrowserBridge.prototype.getNumPassivelyCapturedEvents = function() {
591 return this.numPassivelyCapturedEvents_; 680 return this.numPassivelyCapturedEvents_;
592 }; 681 };
593 682
594 /** 683 /**
684 * Sends each entry to all log observers, and updates |capturedEvents_|.
685 * Also assigns unique ids to log entries without a source.
686 */
687 BrowserBridge.prototype.addLogEntries = function(logEntries) {
688 for (var e = 0; e < logEntries.length; ++e) {
689 var logEntry = logEntries[e];
690
691 // Assign unique ID, if needed.
692 if (logEntry.source.id == 0) {
693 logEntry.source.id = this.nextSourcelessEventId_;
694 --this.nextSourcelessEventId_;
695 }
696 this.capturedEvents_.push(logEntry);
697 for (var i = 0; i < this.logObservers_.length; ++i)
698 this.logObservers_[i].onLogEntryAdded(logEntry);
699 }
700 };
701
702 /**
595 * Deletes captured events with source IDs in |sourceIds|. 703 * Deletes captured events with source IDs in |sourceIds|.
596 */ 704 */
597 BrowserBridge.prototype.deleteEventsBySourceId = function(sourceIds) { 705 BrowserBridge.prototype.deleteEventsBySourceId = function(sourceIds) {
598 var sourceIdDict = {}; 706 var sourceIdDict = {};
599 for (var i = 0; i < sourceIds.length; i++) 707 for (var i = 0; i < sourceIds.length; i++)
600 sourceIdDict[sourceIds[i]] = true; 708 sourceIdDict[sourceIds[i]] = true;
601 709
602 var newEventList = []; 710 var newEventList = [];
603 for (var i = 0; i < this.capturedEvents_.length; ++i) { 711 for (var i = 0; i < this.capturedEvents_.length; ++i) {
604 var id = this.capturedEvents_[i].source.id; 712 var id = this.capturedEvents_[i].source.id;
(...skipping 14 matching lines...) Expand all
619 * Deletes all captured events. 727 * Deletes all captured events.
620 */ 728 */
621 BrowserBridge.prototype.deleteAllEvents = function() { 729 BrowserBridge.prototype.deleteAllEvents = function() {
622 this.capturedEvents_ = []; 730 this.capturedEvents_ = [];
623 this.numPassivelyCapturedEvents_ = 0; 731 this.numPassivelyCapturedEvents_ = 0;
624 for (var i = 0; i < this.logObservers_.length; ++i) 732 for (var i = 0; i < this.logObservers_.length; ++i)
625 this.logObservers_[i].onAllLogEntriesDeleted(); 733 this.logObservers_[i].onAllLogEntriesDeleted();
626 }; 734 };
627 735
628 /** 736 /**
737 * Informs log observers whether or not future events will be from a log file.
738 * Hides all tabs except the events and data tabs when viewing a log file, shows
739 * them all otherwise.
740 */
741 BrowserBridge.prototype.setIsViewingLogFile_ = function(isViewingLogFile) {
742 this.isViewingLogFile_ = isViewingLogFile;
743 var tabIds = this.categoryTabSwitcher_.getAllTabIds();
744
745 for (var i = 0; i < this.logObservers_.length; ++i)
746 this.logObservers_[i].onSetIsViewingLogFile(isViewingLogFile);
747
748 // Shows/hides tabs not used when viewing a log file.
749 for (var i = 0; i < tabIds.length; ++i) {
750 if (tabIds[i] == 'eventsTab' || tabIds[i] == 'dataTab')
751 continue;
752 this.categoryTabSwitcher_.showTabHandleNode(tabIds[i], !isViewingLogFile);
753 }
754
755 if (isViewingLogFile) {
756 var activeTab = this.categoryTabSwitcher_.findActiveTab();
757 if (activeTab.id != 'eventsTab')
758 this.categoryTabSwitcher_.switchToTab('dataTab', null);
759 }
760 };
761
762 /**
763 * Returns true if a log file is currently being viewed.
764 */
765 BrowserBridge.prototype.isViewingLogFile = function() {
766 return this.isViewingLogFile_;
767 };
768
769 /**
629 * If |force| is true, calls all startUpdate functions. Otherwise, just 770 * If |force| is true, calls all startUpdate functions. Otherwise, just
630 * runs updates with active observers. 771 * runs updates with active observers.
631 */ 772 */
632 BrowserBridge.prototype.checkForUpdatedInfo = function(force) { 773 BrowserBridge.prototype.checkForUpdatedInfo = function(force) {
633 for (name in this.pollableDataHelpers_) { 774 for (name in this.pollableDataHelpers_) {
634 var helper = this.pollableDataHelpers_[name]; 775 var helper = this.pollableDataHelpers_[name];
635 if (force || helper.hasActiveObserver()) 776 if (force || helper.hasActiveObserver())
636 helper.startUpdate(); 777 helper.startUpdate();
637 } 778 }
638 }; 779 };
(...skipping 116 matching lines...) Expand 10 before | Expand all | Expand 10 after
755 return true; 896 return true;
756 }; 897 };
757 898
758 UpdateAllObserver.prototype.onDataReceived_ = function(helper, name, data) { 899 UpdateAllObserver.prototype.onDataReceived_ = function(helper, name, data) {
759 helper.removeObserver(this); 900 helper.removeObserver(this);
760 --this.observingCount_; 901 --this.observingCount_;
761 this.updatedData_[name] = data; 902 this.updatedData_[name] = data;
762 if (this.observingCount_ == 0) 903 if (this.observingCount_ == 0)
763 this.callback_(this.updatedData_); 904 this.callback_(this.updatedData_);
764 }; 905 };
OLDNEW
« no previous file with comments | « chrome/browser/resources/net_internals/index.html ('k') | chrome/browser/resources/net_internals/proxyview.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698