1 // Copyright (c) 2012 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.
5 log_util
= (function() {
9 * Creates a new log dump. |events| is a list of all events, |polledData| is
10 * an object containing the results of each poll, |tabData| is an object
11 * containing data for individual tabs, |date| is the time the dump was
12 * created, as a formatted string, and |privacyStripping| is whether or not
13 * private information should be removed from the generated dump.
15 * Returns the new log dump as an object. Resulting object may have a null
18 * TODO(eroman): Use javadoc notation for these parameters.
20 * Log dumps are just JSON objects containing five values:
22 * |userComments| User-provided notes describing what this dump file is
24 * |constants| needed to interpret the data. This also includes some
25 * browser state information.
26 * |events| from the NetLog.
27 * |polledData| from each PollableDataHelper available on the source OS.
28 * |tabData| containing any tab-specific state that's not present in
31 * |polledData| and |tabData| may be empty objects, or may be missing data for
32 * tabs not present on the OS the log is from.
34 function createLogDump(userComments
, constants
, events
, polledData
, tabData
,
35 numericDate
, privacyStripping
) {
37 events
= events
.map(stripCookiesAndLoginInfo
);
40 'userComments': userComments
,
41 'constants': constants
,
43 'polledData': polledData
,
47 // Not technically client info, but it's used at the same point in the code.
48 if (numericDate
&& constants
.clientInfo
) {
49 constants
.clientInfo
.numericDate
= numericDate
;
56 * Returns a new log dump created using the polled data and date from the
57 * |oldLogDump|. The other parts of the log dump come from current
58 * net-internals state.
60 function createUpdatedLogDump(userComments
, oldLogDump
, privacyStripping
) {
61 var numericDate
= null;
62 if (oldLogDump
.constants
.clientInfo
&&
63 oldLogDump
.constants
.clientInfo
.numericDate
) {
64 numericDate
= oldLogDump
.constants
.clientInfo
.numericDate
;
66 var logDump
= createLogDump(
69 EventsTracker
.getInstance().getAllCapturedEvents(),
70 oldLogDump
.polledData
,
74 return JSON
.stringify(logDump
);
78 * Creates a full log dump using |polledData| and the return value of each
79 * tab's saveState function and passes it to |callback|.
81 function onUpdateAllCompleted(userComments
, callback
, privacyStripping
,
83 var logDump
= createLogDump(
86 EventsTracker
.getInstance().getAllCapturedEvents(),
89 timeutil
.getCurrentTime(),
91 callback(JSON
.stringify(logDump
));
95 * Called to create a new log dump. Must not be called once a dump has been
96 * loaded. Once a log dump has been created, |callback| is passed the dumped
99 function createLogDumpAsync(userComments
, callback
, privacyStripping
) {
100 g_browser
.updateAllInfo(
101 onUpdateAllCompleted
.bind(null, userComments
, callback
,
106 * Gather any tab-specific state information prior to creating a log dump.
108 function getTabData_() {
110 var tabSwitcher
= MainView
.getInstance().tabSwitcher();
111 var tabIdToView
= tabSwitcher
.getAllTabViews();
112 for (var tabId
in tabIdToView
) {
113 var view
= tabIdToView
[tabId
];
115 tabData
[tabId
] = view
.saveState();
120 * Loads a full log dump. Returns a string containing a log of the load.
121 * |opt_fileName| should always be given when loading from a file, instead of
122 * from a log dump generated in-memory.
123 * The process goes like this:
124 * 1) Load constants. If this fails, or the version number can't be handled,
125 * abort the load. If this step succeeds, the load cannot be aborted.
126 * 2) Clear all events. Any event observers are informed of the clear as
128 * 3) Call onLoadLogStart(polledData, tabData) for each view with an
129 * onLoadLogStart function. This allows tabs to clear any extra state
130 * that would affect the next step. |polledData| contains the data polled
131 * for all helpers, but |tabData| contains only the data from that
133 * 4) Add all events from the log file.
134 * 5) Call onLoadLogFinish(polledData, tabData) for each view with an
135 * onLoadLogFinish function. The arguments are the same as in step 3. If
136 * there is no onLoadLogFinish function, it throws an exception, or it
137 * returns false instead of true, the data dump is assumed to contain no
138 * valid data for the tab, so the tab is hidden. Otherwise, the tab is
141 function loadLogDump(logDump
, opt_fileName
) {
142 // Perform minimal validity check, and abort if it fails.
143 if (typeof(logDump
) != 'object')
144 return 'Load failed. Top level JSON data is not an object.';
146 // String listing text summary of load errors, if any.
147 var errorString
= '';
149 if (!areValidConstants(logDump
.constants
))
150 errorString
+= 'Invalid constants object.\n';
151 if (typeof(logDump
.events
) != 'object')
152 errorString
+= 'NetLog events missing.\n';
153 if (typeof(logDump
.constants
.logFormatVersion
) != 'number')
154 errorString
+= 'Invalid version number.\n';
156 if (errorString
.length
> 0)
157 return 'Load failed:\n\n' + errorString
;
159 if (typeof(logDump
.polledData
) != 'object')
160 logDump
.polledData
= {};
161 if (typeof(logDump
.tabData
) != 'object')
162 logDump
.tabData
= {};
164 if (logDump
.constants
.logFormatVersion
!= Constants
.logFormatVersion
) {
165 return 'Unable to load different log version.' +
166 ' Found ' + logDump
.constants
.logFormatVersion
+
167 ', Expected ' + Constants
.logFormatVersion
;
170 g_browser
.receivedConstants(logDump
.constants
);
172 // Check for validity of each log entry, and then add the ones that pass.
173 // Since the events are kept around, and we can't just hide a single view
174 // on a bad event, we have more error checking for them than other data.
175 var validEvents
= [];
176 var numDeprecatedPassiveEvents
= 0;
177 for (var eventIndex
= 0; eventIndex
< logDump
.events
.length
; ++eventIndex
) {
178 var event
= logDump
.events
[eventIndex
];
179 if (typeof event
== 'object' &&
180 typeof event
.source
== 'object' &&
181 typeof event
.time
== 'string' &&
182 typeof EventTypeNames
[event
.type
] == 'string' &&
183 typeof EventSourceTypeNames
[event
.source
.type
] == 'string' &&
184 getKeyWithValue(EventPhase
, event
.phase
) != '?') {
185 if (event
.wasPassivelyCaptured
) {
186 // NOTE: Up until Chrome 18, log dumps included "passively captured"
187 // events. These are no longer supported, so skip past them
188 // to avoid confusing the rest of the code.
189 numDeprecatedPassiveEvents
++;
192 validEvents
.push(event
);
196 // Make sure the loaded log contained an export date. If not we will
197 // synthesize one. This can legitimately happen for dump files created
198 // via command line flag, or for older dump formats (before Chrome 17).
199 if (typeof logDump
.constants
.clientInfo
.numericDate
!= 'number') {
200 errorString
+= 'The log file is missing clientInfo.numericDate.\n';
202 if (validEvents
.length
> 0) {
204 'Synthesizing export date as time of last event captured.\n';
205 var lastEvent
= validEvents
[validEvents
.length
- 1];
206 ClientInfo
.numericDate
=
207 timeutil
.convertTimeTicksToDate(lastEvent
.time
).getTime();
209 errorString
+= 'Can\'t guess export date!\n';
210 ClientInfo
.numericDate
= 0;
214 // Prevent communication with the browser. Once the constants have been
215 // loaded, it's safer to continue trying to load the log, even in the case
217 MainView
.getInstance().onLoadLog(opt_fileName
);
219 // Delete all events. This will also update all logObservers.
220 EventsTracker
.getInstance().deleteAllLogEntries();
222 // Inform all the views that a log file is being loaded, and pass in
223 // view-specific saved state, if any.
224 var tabSwitcher
= MainView
.getInstance().tabSwitcher();
225 var tabIdToView
= tabSwitcher
.getAllTabViews();
226 for (var tabId
in tabIdToView
) {
227 var view
= tabIdToView
[tabId
];
228 view
.onLoadLogStart(logDump
.polledData
, logDump
.tabData
[tabId
]);
230 EventsTracker
.getInstance().addLogEntries(validEvents
);
232 var numInvalidEvents
= logDump
.events
.length
-
233 (validEvents
.length
+ numDeprecatedPassiveEvents
);
234 if (numInvalidEvents
> 0) {
235 errorString
+= 'Unable to load ' + numInvalidEvents
+
236 ' events, due to invalid data.\n\n';
239 if (numDeprecatedPassiveEvents
> 0) {
240 errorString
+= 'Discarded ' + numDeprecatedPassiveEvents
+
241 ' passively collected events. Use an older version of Chrome to' +
242 ' load this dump if you want to see them.\n\n';
245 // Update all views with data from the file. Show only those views which
246 // successfully load the data.
247 for (var tabId
in tabIdToView
) {
248 var view
= tabIdToView
[tabId
];
249 var showView
= false;
250 // The try block eliminates the need for checking every single value
251 // before trying to access it.
253 if (view
.onLoadLogFinish(logDump
.polledData
,
254 logDump
.tabData
[tabId
],
259 errorString
+= 'Caught error while calling onLoadLogFinish: ' +
262 tabSwitcher
.showMenuItem(tabId
, showView
);
265 return errorString
+ 'Log loaded.';
269 * Loads a log dump from the string |logFileContents|, which can be either a
270 * full net-internals dump, or a NetLog dump only. Returns a string
271 * containing a log of the load.
273 function loadLogFile(logFileContents
, fileName
) {
274 // Try and parse the log dump as a single JSON string. If this succeeds,
275 // it's most likely a full log dump. Otherwise, it may be a dump created by
277 var parsedDump
= null;
278 var errorString
= '';
280 parsedDump
= JSON
.parse(logFileContents
);
283 // We may have a --log-net-log=blah log dump. If so, remove the comma
284 // after the final good entry, and add the necessary close brackets.
285 var end
= Math
.max(logFileContents
.lastIndexOf(',\n'),
286 logFileContents
.lastIndexOf(',\r'));
288 parsedDump
= JSON
.parse(logFileContents
.substring(0, end
) + ']}');
289 errorString
+= 'Log file truncated. Events may be missing.\n';
297 return 'Unable to parse log dump as JSON file.';
298 return errorString
+ loadLogDump(parsedDump
, fileName
);
303 createUpdatedLogDump
: createUpdatedLogDump
,
304 createLogDumpAsync
: createLogDumpAsync
,
305 loadLogFile
: loadLogFile