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