dataview.js revision 3345a6884c488ff3a535c2c9acdd33d74b37e311
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 3// found in the LICENSE file. 4 5/** 6 * This view displays options for importing/exporting the captured data. Its 7 * primarily usefulness is to allow users to copy-paste their data in an easy 8 * to read format for bug reports. 9 * 10 * - Has a button to generate a text report. 11 * 12 * - Shows how many events have been captured. 13 * @constructor 14 */ 15function DataView(mainBoxId, 16 outputTextBoxId, 17 exportTextButtonId, 18 securityStrippingCheckboxId, 19 passivelyCapturedCountId, 20 activelyCapturedCountId, 21 deleteAllId) { 22 DivView.call(this, mainBoxId); 23 24 this.textPre_ = document.getElementById(outputTextBoxId); 25 this.securityStrippingCheckbox_ = 26 document.getElementById(securityStrippingCheckboxId); 27 28 var exportTextButton = document.getElementById(exportTextButtonId); 29 exportTextButton.onclick = this.onExportToText_.bind(this); 30 31 this.activelyCapturedCountBox_ = 32 document.getElementById(activelyCapturedCountId); 33 this.passivelyCapturedCountBox_ = 34 document.getElementById(passivelyCapturedCountId); 35 document.getElementById(deleteAllId).onclick = 36 g_browser.deleteAllEvents.bind(g_browser); 37 38 this.updateEventCounts_(); 39 40 g_browser.addLogObserver(this); 41} 42 43inherits(DataView, DivView); 44 45/** 46 * Called whenever a new event is received. 47 */ 48DataView.prototype.onLogEntryAdded = function(logEntry) { 49 this.updateEventCounts_(); 50}; 51 52/** 53 * Called whenever some log events are deleted. |sourceIds| lists 54 * the source IDs of all deleted log entries. 55 */ 56DataView.prototype.onLogEntriesDeleted = function(sourceIds) { 57 this.updateEventCounts_(); 58}; 59 60/** 61 * Called whenever all log events are deleted. 62 */ 63DataView.prototype.onAllLogEntriesDeleted = function() { 64 this.updateEventCounts_(); 65}; 66 67/** 68 * Updates the counters showing how many events have been captured. 69 */ 70DataView.prototype.updateEventCounts_ = function() { 71 this.activelyCapturedCountBox_.innerText = 72 g_browser.getNumActivelyCapturedEvents() 73 this.passivelyCapturedCountBox_.innerText = 74 g_browser.getNumPassivelyCapturedEvents(); 75}; 76 77/** 78 * Presents the captured data as formatted text. 79 */ 80DataView.prototype.onExportToText_ = function() { 81 this.setText_("Generating..."); 82 83 var text = []; 84 85 // Print some basic information about our environment. 86 text.push('Data exported on: ' + (new Date()).toLocaleString()); 87 text.push(''); 88 text.push('Number of passively captured events: ' + 89 g_browser.getNumPassivelyCapturedEvents()); 90 text.push('Number of actively captured events: ' + 91 g_browser.getNumActivelyCapturedEvents()); 92 text.push(''); 93 94 text.push('Chrome version: ' + ClientInfo.version + 95 ' (' + ClientInfo.official + 96 ' ' + ClientInfo.cl + 97 ') ' + ClientInfo.version_mod); 98 // Third value in first set of parentheses in user-agent string. 99 var platform = /\(.*?;.*?; (.*?);/.exec(navigator.userAgent); 100 if (platform) 101 text.push('Platform: ' + platform[1]); 102 text.push('Command line: ' + ClientInfo.command_line); 103 104 text.push(''); 105 text.push('----------------------------------------------'); 106 text.push(' Proxy settings (effective)'); 107 text.push('----------------------------------------------'); 108 text.push(''); 109 110 text.push(proxySettingsToString( 111 g_browser.proxySettings_.currentData_.effective)); 112 113 text.push(''); 114 text.push('----------------------------------------------'); 115 text.push(' Proxy settings (original)'); 116 text.push('----------------------------------------------'); 117 text.push(''); 118 119 text.push(proxySettingsToString( 120 g_browser.proxySettings_.currentData_.original)); 121 122 text.push(''); 123 text.push('----------------------------------------------'); 124 text.push(' Bad proxies cache'); 125 text.push('----------------------------------------------'); 126 127 var badProxiesList = g_browser.badProxies_.currentData_; 128 if (badProxiesList.length == 0) { 129 text.push(''); 130 text.push('None'); 131 } else { 132 for (var i = 0; i < badProxiesList.length; ++i) { 133 var e = badProxiesList[i]; 134 text.push(''); 135 text.push('(' + (i+1) + ')'); 136 text.push('Proxy: ' + e.proxy_uri); 137 text.push('Bad until: ' + this.formatExpirationTime_(e.bad_until)); 138 } 139 } 140 141 text.push(''); 142 text.push('----------------------------------------------'); 143 text.push(' Host resolver cache'); 144 text.push('----------------------------------------------'); 145 text.push(''); 146 147 var hostResolverCache = g_browser.hostResolverCache_.currentData_; 148 149 text.push('Capcity: ' + hostResolverCache.capacity); 150 text.push('Time to live for successful resolves (ms): ' + 151 hostResolverCache.ttl_success_ms); 152 text.push('Time to live for failed resolves (ms): ' + 153 hostResolverCache.ttl_failure_ms); 154 155 if (hostResolverCache.entries.length > 0) { 156 for (var i = 0; i < hostResolverCache.entries.length; ++i) { 157 var e = hostResolverCache.entries[i]; 158 159 text.push(''); 160 text.push('(' + (i+1) + ')'); 161 text.push('Hostname: ' + e.hostname); 162 text.push('Address family: ' + e.address_family); 163 164 if (e.error != undefined) { 165 text.push('Error: ' + e.error); 166 } else { 167 for (var j = 0; j < e.addresses.length; ++j) { 168 text.push('Address ' + (j + 1) + ': ' + e.addresses[j]); 169 } 170 } 171 172 text.push('Valid until: ' + this.formatExpirationTime_(e.expiration)); 173 var expirationDate = g_browser.convertTimeTicksToDate(e.expiration); 174 text.push(' (' + expirationDate.toLocaleString() + ')'); 175 } 176 } else { 177 text.push(''); 178 text.push('None'); 179 } 180 181 text.push(''); 182 text.push('----------------------------------------------'); 183 text.push(' Events'); 184 text.push('----------------------------------------------'); 185 text.push(''); 186 187 this.appendEventsPrintedAsText_(text); 188 189 text.push(''); 190 text.push('----------------------------------------------'); 191 text.push(' Http cache stats'); 192 text.push('----------------------------------------------'); 193 text.push(''); 194 195 var httpCacheStats = g_browser.httpCacheInfo_.currentData_.stats; 196 for (var statName in httpCacheStats) 197 text.push(statName + ': ' + httpCacheStats[statName]); 198 199 text.push(''); 200 text.push('----------------------------------------------'); 201 text.push(' Socket pools'); 202 text.push('----------------------------------------------'); 203 text.push(''); 204 205 this.appendSocketPoolsAsText_(text); 206 207 if (g_browser.isPlatformWindows()) { 208 text.push(''); 209 text.push('----------------------------------------------'); 210 text.push(' Winsock layered service providers'); 211 text.push('----------------------------------------------'); 212 text.push(''); 213 214 var serviceProviders = g_browser.serviceProviders_.currentData_; 215 var layeredServiceProviders = serviceProviders.service_providers; 216 for (var i = 0; i < layeredServiceProviders.length; ++i) { 217 var provider = layeredServiceProviders[i]; 218 text.push('name: ' + provider.name); 219 text.push('version: ' + provider.version); 220 text.push('type: ' + 221 ServiceProvidersView.getLayeredServiceProviderType(provider)); 222 text.push('socket_type: ' + 223 ServiceProvidersView.getSocketType(provider)); 224 text.push('socket_protocol: ' + 225 ServiceProvidersView.getProtocolType(provider)); 226 text.push('path: ' + provider.path); 227 text.push(''); 228 } 229 230 text.push(''); 231 text.push('----------------------------------------------'); 232 text.push(' Winsock namespace providers'); 233 text.push('----------------------------------------------'); 234 text.push(''); 235 236 var namespaceProviders = serviceProviders.namespace_providers; 237 for (var i = 0; i < namespaceProviders.length; ++i) { 238 var provider = namespaceProviders[i]; 239 text.push('name: ' + provider.name); 240 text.push('version: ' + provider.version); 241 text.push('type: ' + 242 ServiceProvidersView.getNamespaceProviderType(provider)); 243 text.push('active: ' + provider.active); 244 text.push(''); 245 } 246 } 247 248 // Open a new window to display this text. 249 this.setText_(text.join('\n')); 250 251 this.selectText_(); 252}; 253 254DataView.prototype.appendEventsPrintedAsText_ = function(out) { 255 var allEvents = g_browser.getAllCapturedEvents(); 256 257 // Group the events into buckets by source ID, and buckets by source type. 258 var sourceIds = []; 259 var sourceIdToEventList = {}; 260 var sourceTypeToSourceIdList = {}; 261 262 // Lists used for actual output. 263 var eventLists = []; 264 265 for (var i = 0; i < allEvents.length; ++i) { 266 var e = allEvents[i]; 267 var eventList = sourceIdToEventList[e.source.id]; 268 if (!eventList) { 269 eventList = []; 270 eventLists.push(eventList); 271 if (e.source.type != LogSourceType.NONE) 272 sourceIdToEventList[e.source.id] = eventList; 273 274 // Update sourceIds 275 sourceIds.push(e.source.id); 276 277 // Update the sourceTypeToSourceIdList list. 278 var idList = sourceTypeToSourceIdList[e.source.type]; 279 if (!idList) { 280 idList = []; 281 sourceTypeToSourceIdList[e.source.type] = idList; 282 } 283 idList.push(e.source.id); 284 } 285 eventList.push(e); 286 } 287 288 289 // For each source or event without a source (ordered by when the first 290 // output event for that source happened). 291 for (var i = 0; i < eventLists.length; ++i) { 292 var eventList = eventLists[i]; 293 var sourceId = eventList[0].source.id; 294 var sourceType = eventList[0].source.type; 295 296 var startDate = g_browser.convertTimeTicksToDate(eventList[0].time); 297 298 out.push('------------------------------------------'); 299 out.push(getKeyWithValue(LogSourceType, sourceType) + 300 ' (id=' + sourceId + ')' + 301 ' [start=' + startDate.toLocaleString() + ']'); 302 out.push('------------------------------------------'); 303 304 out.push(PrintSourceEntriesAsText(eventList, 305 this.securityStrippingCheckbox_.checked)); 306 } 307}; 308 309DataView.prototype.appendSocketPoolsAsText_ = function(text) { 310 var socketPools = SocketPoolWrapper.createArrayFrom( 311 g_browser.socketPoolInfo_.currentData_); 312 var tablePrinter = SocketPoolWrapper.createTablePrinter(socketPools); 313 text.push(tablePrinter.toText(2)); 314 315 text.push(''); 316 317 for (var i = 0; i < socketPools.length; ++i) { 318 if (socketPools[i].origPool.groups == undefined) 319 continue; 320 var groupTablePrinter = socketPools[i].createGroupTablePrinter(); 321 text.push(groupTablePrinter.toText(2)); 322 } 323}; 324 325/** 326 * Helper function to set this view's content to |text|. 327 */ 328DataView.prototype.setText_ = function(text) { 329 this.textPre_.innerHTML = ''; 330 addTextNode(this.textPre_, text); 331}; 332 333/** 334 * Format a time ticks count as a timestamp. 335 */ 336DataView.prototype.formatExpirationTime_ = function(timeTicks) { 337 var d = g_browser.convertTimeTicksToDate(timeTicks); 338 var isExpired = d.getTime() < (new Date()).getTime(); 339 return 't=' + d.getTime() + (isExpired ? ' [EXPIRED]' : ''); 340}; 341 342/** 343 * Select all text from log dump. 344 */ 345DataView.prototype.selectText_ = function() { 346 var selection = window.getSelection(); 347 selection.removeAllRanges(); 348 349 var range = document.createRange(); 350 range.selectNodeContents(this.textPre_); 351 selection.addRange(range); 352}; 353