// Copyright 2006 The Closure Library Authors. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS-IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. /** * @fileoverview Definition of the DebugWindow class. Please minimize * dependencies this file has on other closure classes as any dependency it * takes won't be able to use the logging infrastructure. * */ goog.provide('goog.debug.DebugWindow'); goog.require('goog.debug.HtmlFormatter'); goog.require('goog.debug.LogManager'); goog.require('goog.structs.CircularBuffer'); goog.require('goog.userAgent'); /** * Provides a debug DebugWindow that is bound to the goog.debug.Logger. * It handles log messages and writes them to the DebugWindow. This doesn't * provide a lot of functionality that the old Gmail logging infrastructure * provided like saving debug logs for exporting to the server. Now that we * have an event-based logging infrastructure, we can encapsulate that * functionality in a separate class. * * @constructor * @param {string=} opt_identifier Identifier for this logging class. * @param {string=} opt_prefix Prefix prepended to messages. */ goog.debug.DebugWindow = function(opt_identifier, opt_prefix) { /** * Identifier for this logging class * @type {string} * @protected * @suppress {underscore} */ this.identifier_ = opt_identifier || ''; /** * Optional prefix to be prepended to error strings * @type {string} * @private */ this.prefix_ = opt_prefix || ''; /** * Array used to buffer log output * @type {Array} * @protected * @suppress {underscore} */ this.outputBuffer_ = []; /** * Buffer for saving the last 1000 messages * @type {goog.structs.CircularBuffer} * @private */ this.savedMessages_ = new goog.structs.CircularBuffer(goog.debug.DebugWindow.MAX_SAVED); /** * Save the publish handler so it can be removed * @type {Function} * @private */ this.publishHandler_ = goog.bind(this.addLogRecord, this); /** * Formatter for formatted output * @type {goog.debug.Formatter} * @private */ this.formatter_ = new goog.debug.HtmlFormatter(this.prefix_); /** * Loggers that we shouldn't output * @type {Object} * @private */ this.filteredLoggers_ = {}; // enable by default this.setCapturing(true); /** * Whether we are currently enabled. When the DebugWindow is enabled, it tries * to keep its window open. When it's disabled, it can still be capturing log * output if, but it won't try to write them to the DebugWindow window until * it's enabled. * @type {boolean} * @private */ this.enabled_ = goog.debug.DebugWindow.isEnabled(this.identifier_); // timer to save the DebugWindow's window position in a cookie goog.global.setInterval(goog.bind(this.saveWindowPositionSize_, this), 7500); }; /** * Max number of messages to be saved * @type {number} */ goog.debug.DebugWindow.MAX_SAVED = 500; /** * How long to keep the cookies for in milliseconds * @type {number} */ goog.debug.DebugWindow.COOKIE_TIME = 30 * 24 * 60 * 60 * 1000; // 30-days /** * HTML string printed when the debug window opens * @type {string} * @protected */ goog.debug.DebugWindow.prototype.welcomeMessage = 'LOGGING'; /** * Whether to force enable the window on a severe log. * @type {boolean} * @private */ goog.debug.DebugWindow.prototype.enableOnSevere_ = false; /** * Reference to debug window * @type {Window} * @protected * @suppress {underscore} */ goog.debug.DebugWindow.prototype.win_ = null; /** * In the process of opening the window * @type {boolean} * @private */ goog.debug.DebugWindow.prototype.winOpening_ = false; /** * Whether we are currently capturing logger output. * * @type {boolean} * @private */ goog.debug.DebugWindow.prototype.isCapturing_ = false; /** * Whether we already showed an alert that the DebugWindow was blocked. * @type {boolean} * @private */ goog.debug.DebugWindow.showedBlockedAlert_ = false; /** * Reference to timeout used to buffer the output stream. * @type {?number} * @private */ goog.debug.DebugWindow.prototype.bufferTimeout_ = null; /** * Timestamp for the last time the log was written to. * @type {number} * @protected * @suppress {underscore} */ goog.debug.DebugWindow.prototype.lastCall_ = goog.now(); /** * Sets the welcome message shown when the window is first opened or reset. * * @param {string} msg An HTML string. */ goog.debug.DebugWindow.prototype.setWelcomeMessage = function(msg) { this.welcomeMessage = msg; }; /** * Initializes the debug window. */ goog.debug.DebugWindow.prototype.init = function() { if (this.enabled_) { this.openWindow_(); } }; /** * Whether the DebugWindow is enabled. When the DebugWindow is enabled, it * tries to keep its window open and logs all messages to the window. When the * DebugWindow is disabled, it stops logging messages to its window. * * @return {boolean} Whether the DebugWindow is enabled. */ goog.debug.DebugWindow.prototype.isEnabled = function() { return this.enabled_; }; /** * Sets whether the DebugWindow is enabled. When the DebugWindow is enabled, it * tries to keep its window open and log all messages to the window. When the * DebugWindow is disabled, it stops logging messages to its window. The * DebugWindow also saves this state to a cookie so that it's persisted across * application refreshes. * @param {boolean} enable Whether the DebugWindow is enabled. */ goog.debug.DebugWindow.prototype.setEnabled = function(enable) { this.enabled_ = enable; if (this.enabled_) { this.openWindow_(); } this.setCookie_('enabled', enable ? '1' : '0'); }; /** * Sets whether the debug window should be force enabled when a severe log is * encountered. * @param {boolean} enableOnSevere Whether to enable on severe logs.. */ goog.debug.DebugWindow.prototype.setForceEnableOnSevere = function(enableOnSevere) { this.enableOnSevere_ = enableOnSevere; }; /** * Whether we are currently capturing logger output. * @return {boolean} whether we are currently capturing logger output. */ goog.debug.DebugWindow.prototype.isCapturing = function() { return this.isCapturing_; }; /** * Sets whether we are currently capturing logger output. * @param {boolean} capturing Whether to capture logger output. */ goog.debug.DebugWindow.prototype.setCapturing = function(capturing) { if (capturing == this.isCapturing_) { return; } this.isCapturing_ = capturing; // attach or detach handler from the root logger var rootLogger = goog.debug.LogManager.getRoot(); if (capturing) { rootLogger.addHandler(this.publishHandler_); } else { rootLogger.removeHandler(this.publishHandler_); } }; /** * Gets the formatter for outputting to the debug window. The default formatter * is an instance of goog.debug.HtmlFormatter * @return {goog.debug.Formatter} The formatter in use. */ goog.debug.DebugWindow.prototype.getFormatter = function() { return this.formatter_; }; /** * Sets the formatter for outputting to the debug window. * @param {goog.debug.Formatter} formatter The formatter to use. */ goog.debug.DebugWindow.prototype.setFormatter = function(formatter) { this.formatter_ = formatter; }; /** * Adds a separator to the debug window. */ goog.debug.DebugWindow.prototype.addSeparator = function() { this.write_('