# lib/goog/debug/logger.js

    1// Copyright 2006 The Closure Library Authors. All Rights Reserved.2//3// Licensed under the Apache License, Version 2.0 (the "License");4// you may not use this file except in compliance with the License.5// You may obtain a copy of the License at6//7//      http://www.apache.org/licenses/LICENSE-2.08//9// Unless required by applicable law or agreed to in writing, software10// distributed under the License is distributed on an "AS-IS" BASIS,11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.12// See the License for the specific language governing permissions and13// limitations under the License.1415/**16 * @fileoverview Definition of the Logger class. Please minimize dependencies17 * this file has on other closure classes as any dependency it takes won't be18 * able to use the logging infrastructure.19 *20 * @see ../demos/debug.html21 */2223goog.provide('goog.debug.LogManager');24goog.provide('goog.debug.Loggable');25goog.provide('goog.debug.Logger');26goog.provide('goog.debug.Logger.Level');2728goog.require('goog.array');29goog.require('goog.asserts');30goog.require('goog.debug');31goog.require('goog.debug.LogBuffer');32goog.require('goog.debug.LogRecord');333435/**36 * A message value that can be handled by a Logger.37 *38 * Functions are treated like callbacks, but are only called when the event's39 * log level is enabled. This is useful for logging messages that are expensive40 * to construct.41 *42 * @typedef {string|function(): string}43 */44goog.debug.Loggable;45464748/**49 * The Logger is an object used for logging debug messages. Loggers are50 * normally named, using a hierarchical dot-separated namespace. Logger names51 * can be arbitrary strings, but they should normally be based on the package52 * name or class name of the logged component, such as goog.net.BrowserChannel.53 *54 * The Logger object is loosely based on the java class55 * java.util.logging.Logger. It supports different levels of filtering for56 * different loggers.57 *58 * The logger object should never be instantiated by application code. It59 * should always use the goog.debug.Logger.getLogger function.60 *61 * @constructor62 * @param {string} name The name of the Logger.63 * @final64 */65goog.debug.Logger = function(name) {66  /**67   * Name of the Logger. Generally a dot-separated namespace68   * @private {string}69   */70  this.name_ = name;7172  /**73   * Parent Logger.74   * @private {goog.debug.Logger}75   */76  this.parent_ = null;7778  /**79   * Level that this logger only filters above. Null indicates it should80   * inherit from the parent.81   * @private {goog.debug.Logger.Level}82   */83  this.level_ = null;8485  /**86   * Map of children loggers. The keys are the leaf names of the children and87   * the values are the child loggers.88   * @private {Object}89   */90  this.children_ = null;9192  /**93   * Handlers that are listening to this logger.94   * @private {Array.<Function>}95   */96  this.handlers_ = null;97};9899100/** @const */101goog.debug.Logger.ROOT_LOGGER_NAME = '';102103104/**105 * @define {boolean} Toggles whether loggers other than the root logger can have106 *     log handlers attached to them and whether they can have their log level107 *     set. Logging is a bit faster when this is set to false.108 */109goog.define('goog.debug.Logger.ENABLE_HIERARCHY', true);110111112if (!goog.debug.Logger.ENABLE_HIERARCHY) {113  /**114   * @type {!Array.<Function>}115   * @private116   */117  goog.debug.Logger.rootHandlers_ = [];118119120  /**121   * @type {goog.debug.Logger.Level}122   * @private123   */124  goog.debug.Logger.rootLevel_;125}126127128129/**130 * The Level class defines a set of standard logging levels that131 * can be used to control logging output.  The logging Level objects132 * are ordered and are specified by ordered integers.  Enabling logging133 * at a given level also enables logging at all higher levels.134 * <p>135 * Clients should normally use the predefined Level constants such136 * as Level.SEVERE.137 * <p>138 * The levels in descending order are:139 * <ul>140 * <li>SEVERE (highest value)141 * <li>WARNING142 * <li>INFO143 * <li>CONFIG144 * <li>FINE145 * <li>FINER146 * <li>FINEST  (lowest value)147 * </ul>148 * In addition there is a level OFF that can be used to turn149 * off logging, and a level ALL that can be used to enable150 * logging of all messages.151 *152 * @param {string} name The name of the level.153 * @param {number} value The numeric value of the level.154 * @constructor155 * @final156 */157goog.debug.Logger.Level = function(name, value) {158  /**159   * The name of the level160   * @type {string}161   */162  this.name = name;163164  /**165   * The numeric value of the level166   * @type {number}167   */168  this.value = value;169};170171172/**173 * @return {string} String representation of the logger level.174 * @override175 */176goog.debug.Logger.Level.prototype.toString = function() {177  return this.name;178};179180181/**182 * OFF is a special level that can be used to turn off logging.183 * This level is initialized to <CODE>Infinity</CODE>.184 * @type {!goog.debug.Logger.Level}185 */186goog.debug.Logger.Level.OFF =187    new goog.debug.Logger.Level('OFF', Infinity);188189190/**191 * SHOUT is a message level for extra debugging loudness.192 * This level is initialized to <CODE>1200</CODE>.193 * @type {!goog.debug.Logger.Level}194 */195goog.debug.Logger.Level.SHOUT = new goog.debug.Logger.Level('SHOUT', 1200);196197198/**199 * SEVERE is a message level indicating a serious failure.200 * This level is initialized to <CODE>1000</CODE>.201 * @type {!goog.debug.Logger.Level}202 */203goog.debug.Logger.Level.SEVERE = new goog.debug.Logger.Level('SEVERE', 1000);204205206/**207 * WARNING is a message level indicating a potential problem.208 * This level is initialized to <CODE>900</CODE>.209 * @type {!goog.debug.Logger.Level}210 */211goog.debug.Logger.Level.WARNING = new goog.debug.Logger.Level('WARNING', 900);212213214/**215 * INFO is a message level for informational messages.216 * This level is initialized to <CODE>800</CODE>.217 * @type {!goog.debug.Logger.Level}218 */219goog.debug.Logger.Level.INFO = new goog.debug.Logger.Level('INFO', 800);220221222/**223 * CONFIG is a message level for static configuration messages.224 * This level is initialized to <CODE>700</CODE>.225 * @type {!goog.debug.Logger.Level}226 */227goog.debug.Logger.Level.CONFIG = new goog.debug.Logger.Level('CONFIG', 700);228229230/**231 * FINE is a message level providing tracing information.232 * This level is initialized to <CODE>500</CODE>.233 * @type {!goog.debug.Logger.Level}234 */235goog.debug.Logger.Level.FINE = new goog.debug.Logger.Level('FINE', 500);236237238/**239 * FINER indicates a fairly detailed tracing message.240 * This level is initialized to <CODE>400</CODE>.241 * @type {!goog.debug.Logger.Level}242 */243goog.debug.Logger.Level.FINER = new goog.debug.Logger.Level('FINER', 400);244245/**246 * FINEST indicates a highly detailed tracing message.247 * This level is initialized to <CODE>300</CODE>.248 * @type {!goog.debug.Logger.Level}249 */250251goog.debug.Logger.Level.FINEST = new goog.debug.Logger.Level('FINEST', 300);252253254/**255 * ALL indicates that all messages should be logged.256 * This level is initialized to <CODE>0</CODE>.257 * @type {!goog.debug.Logger.Level}258 */259goog.debug.Logger.Level.ALL = new goog.debug.Logger.Level('ALL', 0);260261262/**263 * The predefined levels.264 * @type {!Array.<!goog.debug.Logger.Level>}265 * @final266 */267goog.debug.Logger.Level.PREDEFINED_LEVELS = [268  goog.debug.Logger.Level.OFF,269  goog.debug.Logger.Level.SHOUT,270  goog.debug.Logger.Level.SEVERE,271  goog.debug.Logger.Level.WARNING,272  goog.debug.Logger.Level.INFO,273  goog.debug.Logger.Level.CONFIG,274  goog.debug.Logger.Level.FINE,275  goog.debug.Logger.Level.FINER,276  goog.debug.Logger.Level.FINEST,277  goog.debug.Logger.Level.ALL];278279280/**281 * A lookup map used to find the level object based on the name or value of282 * the level object.283 * @type {Object}284 * @private285 */286goog.debug.Logger.Level.predefinedLevelsCache_ = null;287288289/**290 * Creates the predefined levels cache and populates it.291 * @private292 */293goog.debug.Logger.Level.createPredefinedLevelsCache_ = function() {294  goog.debug.Logger.Level.predefinedLevelsCache_ = {};295  for (var i = 0, level; level = goog.debug.Logger.Level.PREDEFINED_LEVELS[i];296       i++) {297    goog.debug.Logger.Level.predefinedLevelsCache_[level.value] = level;298    goog.debug.Logger.Level.predefinedLevelsCache_[level.name] = level;299  }300};301302303/**304 * Gets the predefined level with the given name.305 * @param {string} name The name of the level.306 * @return {goog.debug.Logger.Level} The level, or null if none found.307 */308goog.debug.Logger.Level.getPredefinedLevel = function(name) {309  if (!goog.debug.Logger.Level.predefinedLevelsCache_) {310    goog.debug.Logger.Level.createPredefinedLevelsCache_();311  }312313  return goog.debug.Logger.Level.predefinedLevelsCache_[name] || null;314};315316317/**318 * Gets the highest predefined level <= #value.319 * @param {number} value Level value.320 * @return {goog.debug.Logger.Level} The level, or null if none found.321 */322goog.debug.Logger.Level.getPredefinedLevelByValue = function(value) {323  if (!goog.debug.Logger.Level.predefinedLevelsCache_) {324    goog.debug.Logger.Level.createPredefinedLevelsCache_();325  }326327  if (value in goog.debug.Logger.Level.predefinedLevelsCache_) {328    return goog.debug.Logger.Level.predefinedLevelsCache_[value];329  }330331  for (var i = 0; i < goog.debug.Logger.Level.PREDEFINED_LEVELS.length; ++i) {332    var level = goog.debug.Logger.Level.PREDEFINED_LEVELS[i];333    if (level.value <= value) {334      return level;335    }336  }337  return null;338};339340341/**342 * Finds or creates a logger for a named subsystem. If a logger has already been343 * created with the given name it is returned. Otherwise a new logger is344 * created. If a new logger is created its log level will be configured based345 * on the LogManager configuration and it will configured to also send logging346 * output to its parent's handlers. It will be registered in the LogManager347 * global namespace.348 *349 * @param {string} name A name for the logger. This should be a dot-separated350 * name and should normally be based on the package name or class name of the351 * subsystem, such as goog.net.BrowserChannel.352 * @return {!goog.debug.Logger} The named logger.353 * @deprecated use goog.log instead. http://go/goog-debug-logger-deprecated354 */355goog.debug.Logger.getLogger = function(name) {356  return goog.debug.LogManager.getLogger(name);357};358359360/**361 * Logs a message to profiling tools, if available.362 * {@see https://developers.google.com/web-toolkit/speedtracer/logging-api}363 * {@see http://msdn.microsoft.com/en-us/library/dd433074(VS.85).aspx}364 * @param {string} msg The message to log.365 */366goog.debug.Logger.logToProfilers = function(msg) {367  // Using goog.global, as loggers might be used in window-less contexts.368  if (goog.global['console']) {369    if (goog.global['console']['timeStamp']) {370      // Logs a message to Firebug, Web Inspector, SpeedTracer, etc.371      goog.global['console']['timeStamp'](msg);372    } else if (goog.global['console']['markTimeline']) {373      // TODO(user): markTimeline is deprecated. Drop this else clause entirely374      // after Chrome M14 hits stable.375      goog.global['console']['markTimeline'](msg);376    }377  }378379  if (goog.global['msWriteProfilerMark']) {380    // Logs a message to the Microsoft profiler381    goog.global['msWriteProfilerMark'](msg);382  }383};384385386/**387 * Gets the name of this logger.388 * @return {string} The name of this logger.389 */390goog.debug.Logger.prototype.getName = function() {391  return this.name_;392};393394395/**396 * Adds a handler to the logger. This doesn't use the event system because397 * we want to be able to add logging to the event system.398 * @param {Function} handler Handler function to add.399 */400goog.debug.Logger.prototype.addHandler = function(handler) {401  if (goog.debug.LOGGING_ENABLED) {402    if (goog.debug.Logger.ENABLE_HIERARCHY) {403      if (!this.handlers_) {404        this.handlers_ = [];405      }406      this.handlers_.push(handler);407    } else {408      goog.asserts.assert(!this.name_,409          'Cannot call addHandler on a non-root logger when ' +410          'goog.debug.Logger.ENABLE_HIERARCHY is false.');411      goog.debug.Logger.rootHandlers_.push(handler);412    }413  }414};415416417/**418 * Removes a handler from the logger. This doesn't use the event system because419 * we want to be able to add logging to the event system.420 * @param {Function} handler Handler function to remove.421 * @return {boolean} Whether the handler was removed.422 */423goog.debug.Logger.prototype.removeHandler = function(handler) {424  if (goog.debug.LOGGING_ENABLED) {425    var handlers = goog.debug.Logger.ENABLE_HIERARCHY ? this.handlers_ :426        goog.debug.Logger.rootHandlers_;427    return !!handlers && goog.array.remove(handlers, handler);428  } else {429    return false;430  }431};432433434/**435 * Returns the parent of this logger.436 * @return {goog.debug.Logger} The parent logger or null if this is the root.437 */438goog.debug.Logger.prototype.getParent = function() {439  return this.parent_;440};441442443/**444 * Returns the children of this logger as a map of the child name to the logger.445 * @return {!Object} The map where the keys are the child leaf names and the446 *     values are the Logger objects.447 */448goog.debug.Logger.prototype.getChildren = function() {449  if (!this.children_) {450    this.children_ = {};451  }452  return this.children_;453};454455456/**457 * Set the log level specifying which message levels will be logged by this458 * logger. Message levels lower than this value will be discarded.459 * The level value Level.OFF can be used to turn off logging. If the new level460 * is null, it means that this node should inherit its level from its nearest461 * ancestor with a specific (non-null) level value.462 *463 * @param {goog.debug.Logger.Level} level The new level.464 */465goog.debug.Logger.prototype.setLevel = function(level) {466  if (goog.debug.LOGGING_ENABLED) {467    if (goog.debug.Logger.ENABLE_HIERARCHY) {468      this.level_ = level;469    } else {470      goog.asserts.assert(!this.name_,471          'Cannot call setLevel() on a non-root logger when ' +472          'goog.debug.Logger.ENABLE_HIERARCHY is false.');473      goog.debug.Logger.rootLevel_ = level;474    }475  }476};477478479/**480 * Gets the log level specifying which message levels will be logged by this481 * logger. Message levels lower than this value will be discarded.482 * The level value Level.OFF can be used to turn off logging. If the level483 * is null, it means that this node should inherit its level from its nearest484 * ancestor with a specific (non-null) level value.485 *486 * @return {goog.debug.Logger.Level} The level.487 */488goog.debug.Logger.prototype.getLevel = function() {489  return goog.debug.LOGGING_ENABLED ?490      this.level_ : goog.debug.Logger.Level.OFF;491};492493494/**495 * Returns the effective level of the logger based on its ancestors' levels.496 * @return {goog.debug.Logger.Level} The level.497 */498goog.debug.Logger.prototype.getEffectiveLevel = function() {499  if (!goog.debug.LOGGING_ENABLED) {500    return goog.debug.Logger.Level.OFF;501  }502503  if (!goog.debug.Logger.ENABLE_HIERARCHY) {504    return goog.debug.Logger.rootLevel_;505  }506  if (this.level_) {507    return this.level_;508  }509  if (this.parent_) {510    return this.parent_.getEffectiveLevel();511  }512  goog.asserts.fail('Root logger has no level set.');513  return null;514};515516517/**518 * Checks if a message of the given level would actually be logged by this519 * logger. This check is based on the Loggers effective level, which may be520 * inherited from its parent.521 * @param {goog.debug.Logger.Level} level The level to check.522 * @return {boolean} Whether the message would be logged.523 */524goog.debug.Logger.prototype.isLoggable = function(level) {525  return goog.debug.LOGGING_ENABLED &&526      level.value >= this.getEffectiveLevel().value;527};528529530/**531 * Logs a message. If the logger is currently enabled for the532 * given message level then the given message is forwarded to all the533 * registered output Handler objects.534 * @param {goog.debug.Logger.Level} level One of the level identifiers.535 * @param {goog.debug.Loggable} msg The message to log.536 * @param {Error|Object=} opt_exception An exception associated with the537 *     message.538 */539goog.debug.Logger.prototype.log = function(level, msg, opt_exception) {540  // java caches the effective level, not sure it's necessary here541  if (goog.debug.LOGGING_ENABLED && this.isLoggable(level)) {542    // Message callbacks can be useful when a log message is expensive to build.543    if (goog.isFunction(msg)) {544      msg = msg();545    }546547    this.doLogRecord_(this.getLogRecord(548        level, msg, opt_exception, goog.debug.Logger.prototype.log));549  }550};551552553/**554 * Creates a new log record and adds the exception (if present) to it.555 * @param {goog.debug.Logger.Level} level One of the level identifiers.556 * @param {string} msg The string message.557 * @param {Error|Object=} opt_exception An exception associated with the558 *     message.559 * @param {Function=} opt_fnStackContext A function to use as the base560 *     of the stack trace used in the log record.561 * @return {!goog.debug.LogRecord} A log record.562 * @suppress {es5Strict}563 */564goog.debug.Logger.prototype.getLogRecord = function(565    level, msg, opt_exception, opt_fnStackContext) {566  if (goog.debug.LogBuffer.isBufferingEnabled()) {567    var logRecord =568        goog.debug.LogBuffer.getInstance().addRecord(level, msg, this.name_);569  } else {570    logRecord = new goog.debug.LogRecord(level, String(msg), this.name_);571  }572  if (opt_exception) {573    var context;574    if (goog.STRICT_MODE_COMPATIBLE) {575      context = opt_fnStackContext || goog.debug.Logger.prototype.getLogRecord;576    } else {577      context = opt_fnStackContext || arguments.callee.caller;578    }579580    logRecord.setException(opt_exception);581    logRecord.setExceptionText(582        goog.debug.exposeException(opt_exception,583            opt_fnStackContext || goog.debug.Logger.prototype.getLogRecord));584  }585  return logRecord;586};587588589/**590 * Logs a message at the Logger.Level.SHOUT level.591 * If the logger is currently enabled for the given message level then the592 * given message is forwarded to all the registered output Handler objects.593 * @param {goog.debug.Loggable} msg The message to log.594 * @param {Error=} opt_exception An exception associated with the message.595 */596goog.debug.Logger.prototype.shout = function(msg, opt_exception) {597  if (goog.debug.LOGGING_ENABLED) {598    this.log(goog.debug.Logger.Level.SHOUT, msg, opt_exception);599  }600};601602603/**604 * Logs a message at the Logger.Level.SEVERE level.605 * If the logger is currently enabled for the given message level then the606 * given message is forwarded to all the registered output Handler objects.607 * @param {goog.debug.Loggable} msg The message to log.608 * @param {Error=} opt_exception An exception associated with the message.609 */610goog.debug.Logger.prototype.severe = function(msg, opt_exception) {611  if (goog.debug.LOGGING_ENABLED) {612    this.log(goog.debug.Logger.Level.SEVERE, msg, opt_exception);613  }614};615616617/**618 * Logs a message at the Logger.Level.WARNING level.619 * If the logger is currently enabled for the given message level then the620 * given message is forwarded to all the registered output Handler objects.621 * @param {goog.debug.Loggable} msg The message to log.622 * @param {Error=} opt_exception An exception associated with the message.623 */624goog.debug.Logger.prototype.warning = function(msg, opt_exception) {625  if (goog.debug.LOGGING_ENABLED) {626    this.log(goog.debug.Logger.Level.WARNING, msg, opt_exception);627  }628};629630631/**632 * Logs a message at the Logger.Level.INFO level.633 * If the logger is currently enabled for the given message level then the634 * given message is forwarded to all the registered output Handler objects.635 * @param {goog.debug.Loggable} msg The message to log.636 * @param {Error=} opt_exception An exception associated with the message.637 */638goog.debug.Logger.prototype.info = function(msg, opt_exception) {639  if (goog.debug.LOGGING_ENABLED) {640    this.log(goog.debug.Logger.Level.INFO, msg, opt_exception);641  }642};643644645/**646 * Logs a message at the Logger.Level.CONFIG level.647 * If the logger is currently enabled for the given message level then the648 * given message is forwarded to all the registered output Handler objects.649 * @param {goog.debug.Loggable} msg The message to log.650 * @param {Error=} opt_exception An exception associated with the message.651 */652goog.debug.Logger.prototype.config = function(msg, opt_exception) {653  if (goog.debug.LOGGING_ENABLED) {654    this.log(goog.debug.Logger.Level.CONFIG, msg, opt_exception);655  }656};657658659/**660 * Logs a message at the Logger.Level.FINE level.661 * If the logger is currently enabled for the given message level then the662 * given message is forwarded to all the registered output Handler objects.663 * @param {goog.debug.Loggable} msg The message to log.664 * @param {Error=} opt_exception An exception associated with the message.665 */666goog.debug.Logger.prototype.fine = function(msg, opt_exception) {667  if (goog.debug.LOGGING_ENABLED) {668    this.log(goog.debug.Logger.Level.FINE, msg, opt_exception);669  }670};671672673/**674 * Logs a message at the Logger.Level.FINER level.675 * If the logger is currently enabled for the given message level then the676 * given message is forwarded to all the registered output Handler objects.677 * @param {goog.debug.Loggable} msg The message to log.678 * @param {Error=} opt_exception An exception associated with the message.679 */680goog.debug.Logger.prototype.finer = function(msg, opt_exception) {681  if (goog.debug.LOGGING_ENABLED) {682    this.log(goog.debug.Logger.Level.FINER, msg, opt_exception);683  }684};685686687/**688 * Logs a message at the Logger.Level.FINEST level.689 * If the logger is currently enabled for the given message level then the690 * given message is forwarded to all the registered output Handler objects.691 * @param {goog.debug.Loggable} msg The message to log.692 * @param {Error=} opt_exception An exception associated with the message.693 */694goog.debug.Logger.prototype.finest = function(msg, opt_exception) {695  if (goog.debug.LOGGING_ENABLED) {696    this.log(goog.debug.Logger.Level.FINEST, msg, opt_exception);697  }698};699700701/**702 * Logs a LogRecord. If the logger is currently enabled for the703 * given message level then the given message is forwarded to all the704 * registered output Handler objects.705 * @param {goog.debug.LogRecord} logRecord A log record to log.706 */707goog.debug.Logger.prototype.logRecord = function(logRecord) {708  if (goog.debug.LOGGING_ENABLED && this.isLoggable(logRecord.getLevel())) {709    this.doLogRecord_(logRecord);710  }711};712713714/**715 * Logs a LogRecord.716 * @param {goog.debug.LogRecord} logRecord A log record to log.717 * @private718 */719goog.debug.Logger.prototype.doLogRecord_ = function(logRecord) {720  goog.debug.Logger.logToProfilers('log:' + logRecord.getMessage());721  if (goog.debug.Logger.ENABLE_HIERARCHY) {722    var target = this;723    while (target) {724      target.callPublish_(logRecord);725      target = target.getParent();726    }727  } else {728    for (var i = 0, handler; handler = goog.debug.Logger.rootHandlers_[i++]; ) {729      handler(logRecord);730    }731  }732};733734735/**736 * Calls the handlers for publish.737 * @param {goog.debug.LogRecord} logRecord The log record to publish.738 * @private739 */740goog.debug.Logger.prototype.callPublish_ = function(logRecord) {741  if (this.handlers_) {742    for (var i = 0, handler; handler = this.handlers_[i]; i++) {743      handler(logRecord);744    }745  }746};747748749/**750 * Sets the parent of this logger. This is used for setting up the logger tree.751 * @param {goog.debug.Logger} parent The parent logger.752 * @private753 */754goog.debug.Logger.prototype.setParent_ = function(parent) {755  this.parent_ = parent;756};757758759/**760 * Adds a child to this logger. This is used for setting up the logger tree.761 * @param {string} name The leaf name of the child.762 * @param {goog.debug.Logger} logger The child logger.763 * @private764 */765goog.debug.Logger.prototype.addChild_ = function(name, logger) {766  this.getChildren()[name] = logger;767};768769770/**771 * There is a single global LogManager object that is used to maintain a set of772 * shared state about Loggers and log services. This is loosely based on the773 * java class java.util.logging.LogManager.774 */775goog.debug.LogManager = {};776777778/**779 * Map of logger names to logger objects.780 *781 * @type {!Object.<string, !goog.debug.Logger>}782 * @private783 */784goog.debug.LogManager.loggers_ = {};785786787/**788 * The root logger which is the root of the logger tree.789 * @type {goog.debug.Logger}790 * @private791 */792goog.debug.LogManager.rootLogger_ = null;793794795/**796 * Initializes the LogManager if not already initialized.797 */798goog.debug.LogManager.initialize = function() {799  if (!goog.debug.LogManager.rootLogger_) {800    goog.debug.LogManager.rootLogger_ = new goog.debug.Logger(801        goog.debug.Logger.ROOT_LOGGER_NAME);802    goog.debug.LogManager.loggers_[goog.debug.Logger.ROOT_LOGGER_NAME] =803        goog.debug.LogManager.rootLogger_;804    goog.debug.LogManager.rootLogger_.setLevel(goog.debug.Logger.Level.CONFIG);805  }806};807808809/**810 * Returns all the loggers.811 * @return {!Object.<string, !goog.debug.Logger>} Map of logger names to logger812 *     objects.813 */814goog.debug.LogManager.getLoggers = function() {815  return goog.debug.LogManager.loggers_;816};817818819/**820 * Returns the root of the logger tree namespace, the logger with the empty821 * string as its name.822 *823 * @return {!goog.debug.Logger} The root logger.824 */825goog.debug.LogManager.getRoot = function() {826  goog.debug.LogManager.initialize();827  return /** @type {!goog.debug.Logger} */ (goog.debug.LogManager.rootLogger_);828};829830831/**832 * Finds a named logger.833 *834 * @param {string} name A name for the logger. This should be a dot-separated835 * name and should normally be based on the package name or class name of the836 * subsystem, such as goog.net.BrowserChannel.837 * @return {!goog.debug.Logger} The named logger.838 */839goog.debug.LogManager.getLogger = function(name) {840  goog.debug.LogManager.initialize();841  var ret = goog.debug.LogManager.loggers_[name];842  return ret || goog.debug.LogManager.createLogger_(name);843};844845846/**847 * Creates a function that can be passed to goog.debug.catchErrors. The function848 * will log all reported errors using the given logger.849 * @param {goog.debug.Logger=} opt_logger The logger to log the errors to.850 *     Defaults to the root logger.851 * @return {function(Object)} The created function.852 */853goog.debug.LogManager.createFunctionForCatchErrors = function(opt_logger) {854  return function(info) {855    var logger = opt_logger || goog.debug.LogManager.getRoot();856    logger.severe('Error: ' + info.message + ' (' + info.fileName +857                  ' @ Line: ' + info.line + ')');858  };859};860861862/**863 * Creates the named logger. Will also create the parents of the named logger864 * if they don't yet exist.865 * @param {string} name The name of the logger.866 * @return {!goog.debug.Logger} The named logger.867 * @private868 */869goog.debug.LogManager.createLogger_ = function(name) {870  // find parent logger871  var logger = new goog.debug.Logger(name);872  if (goog.debug.Logger.ENABLE_HIERARCHY) {873    var lastDotIndex = name.lastIndexOf('.');874    var parentName = name.substr(0, lastDotIndex);875    var leafName = name.substr(lastDotIndex + 1);876    var parentLogger = goog.debug.LogManager.getLogger(parentName);877878    // tell the parent about the child and the child about the parent879    parentLogger.addChild_(leafName, logger);880    logger.setParent_(parentLogger);881  }882883  goog.debug.LogManager.loggers_[name] = logger;884  return logger;885};