1 // Copyright 2015 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.
7 * Intercept and record various classes of log messages. By default, such
8 * messages will be reported by Chrome Developer Tools as coming from this
9 * file, making source-line hyperlinks useless. To fix this click the "gear"
10 * icon in Developer Tools, click "Manage framework blocking..." under
11 * "Sources" and add console_wrapper.js as a "Blackbox" component.
15 /** @suppress {duplicate} */
16 var remoting = remoting || {};
24 remoting.ConsoleWrapper = function() {
25 console.assert(instance_ == null,
26 'Duplicate remoting.ConsoleWrapper constructor.');
27 /** @private {number} The number of log entries to save. */
28 this.historyMaxSize_ = 0;
29 /** @private {Array<remoting.ConsoleWrapper.LogEntry>} */
31 /** @private {Object<function(*)>} */
32 this.savedMethods_ = {};
36 * Activate the console wrapper for the specified log types.
38 * @param {number} historyMaxSize The number of log entries to keep.
39 * @param {...remoting.ConsoleWrapper.LogType} var_logTypes The log types to
41 * @suppress {reportUnknownTypes}
43 remoting.ConsoleWrapper.prototype.activate =
44 function(historyMaxSize, var_logTypes) {
45 this.historyMaxSize_ = historyMaxSize;
47 // Restore previous wrappers.
48 for (var key in remoting.ConsoleWrapper.LogType) {
49 var type = remoting.ConsoleWrapper.LogType[key];
50 if (this.savedMethods_[type]) {
51 console[type] = this.savedMethods_[type];
52 delete this.savedMethods_[type];
55 // Activate new wrappers
56 for (var i = 1; i < arguments.length; ++i) {
57 var type = arguments[i];
58 this.savedMethods_[type] = console[type];
59 console[arguments[i]] = this.recordAndLog_.bind(this, arguments[i]);
64 * Deactivate the console wrapper for all log types.
66 remoting.ConsoleWrapper.prototype.deactivate = function() {
71 * @return {Array<remoting.ConsoleWrapper.LogEntry>} The most recent log
72 * entries as configured by activate().
74 remoting.ConsoleWrapper.prototype.getHistory = function() {
79 * @param {remoting.ConsoleWrapper.LogType} type The type of log.
80 * @param {...*} var_args The items to log.
82 * @suppress {reportUnknownTypes}
84 remoting.ConsoleWrapper.prototype.recordAndLog_ =
85 function(type, var_args) {
86 // Construct a new arguments array by removing the first argument.
87 var args = Array.prototype.slice.call(arguments, 1);
88 // Find the caller, ignoring the top-most stack frame.
89 var caller = new base.Callstack().callstack[1];
90 var location = 'unknown';
92 location = caller.file + ':' + caller.line;
95 if (this.historyMaxSize_ > 0) {
98 message: JSON.stringify(args),
100 timestamp: new Date()
102 // Only save assertions if they fail.
103 if (log.type != 'assert' || !args[0]) {
104 this.history_.push(log);
105 if (this.history_.length > this.historyMaxSize_) {
106 this.history_.shift();
110 // Log the message, appending the caller.
111 // TODO(jamiewalch): Make the caller gray so that it's less intrusive. This
112 // can be done using a %c formatter in the first argument, but care needs to
113 // be taken to support the multi-argument case.
115 this.savedMethods_[type].apply(console, args);
119 * @type {remoting.ConsoleWrapper}
121 var instance_ = null;
124 * @return {remoting.ConsoleWrapper} The singleton ConsoleWrapper.
126 remoting.ConsoleWrapper.getInstance = function() {
128 instance_ = new remoting.ConsoleWrapper();
136 * @typedef {{type: string, message: string, caller: string, timestamp: Date}}
138 remoting.ConsoleWrapper.LogEntry;
141 * @enum {string} The log types that can be intercepted. These must match the
142 * names of the corresponding console methods.
144 remoting.ConsoleWrapper.LogType = {