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 at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// 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 and
13// limitations under the License.
14
15/**
16 * @fileoverview Definition of the Logger class. Please minimize dependencies
17 * this file has on other closure classes as any dependency it takes won't be
18 * able to use the logging infrastructure.
19 *
20 * @see ../demos/debug.html
21 */
22
23goog.provide('goog.debug.LogManager');
24goog.provide('goog.debug.Loggable');
25goog.provide('goog.debug.Logger');
26goog.provide('goog.debug.Logger.Level');
27
28goog.require('goog.array');
29goog.require('goog.asserts');
30goog.require('goog.debug');
31goog.require('goog.debug.LogBuffer');
32goog.require('goog.debug.LogRecord');
33
34
35/**
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's
39 * log level is enabled. This is useful for logging messages that are expensive
40 * to construct.
41 *
42 * @typedef {string|function(): string}
43 */
44goog.debug.Loggable;
45
46
47
48/**
49 * The Logger is an object used for logging debug messages. Loggers are
50 * normally named, using a hierarchical dot-separated namespace. Logger names
51 * can be arbitrary strings, but they should normally be based on the package
52 * name or class name of the logged component, such as goog.net.BrowserChannel.
53 *
54 * The Logger object is loosely based on the java class
55 * java.util.logging.Logger. It supports different levels of filtering for
56 * different loggers.
57 *
58 * The logger object should never be instantiated by application code. It
59 * should always use the goog.debug.Logger.getLogger function.
60 *
61 * @constructor
62 * @param {string} name The name of the Logger.
63 * @final
64 */
65goog.debug.Logger = function(name) {
66 /**
67 * Name of the Logger. Generally a dot-separated namespace
68 * @private {string}
69 */
70 this.name_ = name;
71
72 /**
73 * Parent Logger.
74 * @private {goog.debug.Logger}
75 */
76 this.parent_ = null;
77
78 /**
79 * Level that this logger only filters above. Null indicates it should
80 * inherit from the parent.
81 * @private {goog.debug.Logger.Level}
82 */
83 this.level_ = null;
84
85 /**
86 * Map of children loggers. The keys are the leaf names of the children and
87 * the values are the child loggers.
88 * @private {Object}
89 */
90 this.children_ = null;
91
92 /**
93 * Handlers that are listening to this logger.
94 * @private {Array<Function>}
95 */
96 this.handlers_ = null;
97};
98
99
100/** @const */
101goog.debug.Logger.ROOT_LOGGER_NAME = '';
102
103
104/**
105 * @define {boolean} Toggles whether loggers other than the root logger can have
106 * log handlers attached to them and whether they can have their log level
107 * set. Logging is a bit faster when this is set to false.
108 */
109goog.define('goog.debug.Logger.ENABLE_HIERARCHY', true);
110
111
112if (!goog.debug.Logger.ENABLE_HIERARCHY) {
113 /**
114 * @type {!Array<Function>}
115 * @private
116 */
117 goog.debug.Logger.rootHandlers_ = [];
118
119
120 /**
121 * @type {goog.debug.Logger.Level}
122 * @private
123 */
124 goog.debug.Logger.rootLevel_;
125}
126
127
128
129/**
130 * The Level class defines a set of standard logging levels that
131 * can be used to control logging output. The logging Level objects
132 * are ordered and are specified by ordered integers. Enabling logging
133 * at a given level also enables logging at all higher levels.
134 * <p>
135 * Clients should normally use the predefined Level constants such
136 * as Level.SEVERE.
137 * <p>
138 * The levels in descending order are:
139 * <ul>
140 * <li>SEVERE (highest value)
141 * <li>WARNING
142 * <li>INFO
143 * <li>CONFIG
144 * <li>FINE
145 * <li>FINER
146 * <li>FINEST (lowest value)
147 * </ul>
148 * In addition there is a level OFF that can be used to turn
149 * off logging, and a level ALL that can be used to enable
150 * 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 * @constructor
155 * @final
156 */
157goog.debug.Logger.Level = function(name, value) {
158 /**
159 * The name of the level
160 * @type {string}
161 */
162 this.name = name;
163
164 /**
165 * The numeric value of the level
166 * @type {number}
167 */
168 this.value = value;
169};
170
171
172/**
173 * @return {string} String representation of the logger level.
174 * @override
175 */
176goog.debug.Logger.Level.prototype.toString = function() {
177 return this.name;
178};
179
180
181/**
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);
188
189
190/**
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);
196
197
198/**
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);
204
205
206/**
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);
212
213
214/**
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);
220
221
222/**
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);
228
229
230/**
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);
236
237
238/**
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);
244
245/**
246 * FINEST indicates a highly detailed tracing message.
247 * This level is initialized to <CODE>300</CODE>.
248 * @type {!goog.debug.Logger.Level}
249 */
250
251goog.debug.Logger.Level.FINEST = new goog.debug.Logger.Level('FINEST', 300);
252
253
254/**
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);
260
261
262/**
263 * The predefined levels.
264 * @type {!Array<!goog.debug.Logger.Level>}
265 * @final
266 */
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];
278
279
280/**
281 * A lookup map used to find the level object based on the name or value of
282 * the level object.
283 * @type {Object}
284 * @private
285 */
286goog.debug.Logger.Level.predefinedLevelsCache_ = null;
287
288
289/**
290 * Creates the predefined levels cache and populates it.
291 * @private
292 */
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};
301
302
303/**
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 }
312
313 return goog.debug.Logger.Level.predefinedLevelsCache_[name] || null;
314};
315
316
317/**
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 }
326
327 if (value in goog.debug.Logger.Level.predefinedLevelsCache_) {
328 return goog.debug.Logger.Level.predefinedLevelsCache_[value];
329 }
330
331 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};
339
340
341/**
342 * Finds or creates a logger for a named subsystem. If a logger has already been
343 * created with the given name it is returned. Otherwise a new logger is
344 * created. If a new logger is created its log level will be configured based
345 * on the LogManager configuration and it will configured to also send logging
346 * output to its parent's handlers. It will be registered in the LogManager
347 * global namespace.
348 *
349 * @param {string} name A name for the logger. This should be a dot-separated
350 * name and should normally be based on the package name or class name of the
351 * 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-deprecated
354 */
355goog.debug.Logger.getLogger = function(name) {
356 return goog.debug.LogManager.getLogger(name);
357};
358
359
360/**
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 entirely
374 // after Chrome M14 hits stable.
375 goog.global['console']['markTimeline'](msg);
376 }
377 }
378
379 if (goog.global['msWriteProfilerMark']) {
380 // Logs a message to the Microsoft profiler
381 goog.global['msWriteProfilerMark'](msg);
382 }
383};
384
385
386/**
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};
393
394
395/**
396 * Adds a handler to the logger. This doesn't use the event system because
397 * 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};
415
416
417/**
418 * Removes a handler from the logger. This doesn't use the event system because
419 * 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};
432
433
434/**
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};
441
442
443/**
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 the
446 * 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};
454
455
456/**
457 * Set the log level specifying which message levels will be logged by this
458 * 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 level
460 * is null, it means that this node should inherit its level from its nearest
461 * 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};
477
478
479/**
480 * Gets the log level specifying which message levels will be logged by this
481 * 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 level
483 * is null, it means that this node should inherit its level from its nearest
484 * 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};
492
493
494/**
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 }
502
503 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};
515
516
517/**
518 * Checks if a message of the given level would actually be logged by this
519 * logger. This check is based on the Loggers effective level, which may be
520 * 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};
528
529
530/**
531 * Logs a message. If the logger is currently enabled for the
532 * given message level then the given message is forwarded to all the
533 * 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 the
537 * message.
538 */
539goog.debug.Logger.prototype.log = function(level, msg, opt_exception) {
540 // java caches the effective level, not sure it's necessary here
541 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 }
546
547 this.doLogRecord_(this.getLogRecord(
548 level, msg, opt_exception, goog.debug.Logger.prototype.log));
549 }
550};
551
552
553/**
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 the
558 * message.
559 * @param {Function=} opt_fnStackContext A function to use as the base
560 * 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 }
579
580 logRecord.setException(opt_exception);
581 logRecord.setExceptionText(
582 goog.debug.exposeException(opt_exception, context));
583 }
584 return logRecord;
585};
586
587
588/**
589 * Logs a message at the Logger.Level.SHOUT level.
590 * If the logger is currently enabled for the given message level then the
591 * given message is forwarded to all the registered output Handler objects.
592 * @param {goog.debug.Loggable} msg The message to log.
593 * @param {Error=} opt_exception An exception associated with the message.
594 */
595goog.debug.Logger.prototype.shout = function(msg, opt_exception) {
596 if (goog.debug.LOGGING_ENABLED) {
597 this.log(goog.debug.Logger.Level.SHOUT, msg, opt_exception);
598 }
599};
600
601
602/**
603 * Logs a message at the Logger.Level.SEVERE level.
604 * If the logger is currently enabled for the given message level then the
605 * given message is forwarded to all the registered output Handler objects.
606 * @param {goog.debug.Loggable} msg The message to log.
607 * @param {Error=} opt_exception An exception associated with the message.
608 */
609goog.debug.Logger.prototype.severe = function(msg, opt_exception) {
610 if (goog.debug.LOGGING_ENABLED) {
611 this.log(goog.debug.Logger.Level.SEVERE, msg, opt_exception);
612 }
613};
614
615
616/**
617 * Logs a message at the Logger.Level.WARNING level.
618 * If the logger is currently enabled for the given message level then the
619 * given message is forwarded to all the registered output Handler objects.
620 * @param {goog.debug.Loggable} msg The message to log.
621 * @param {Error=} opt_exception An exception associated with the message.
622 */
623goog.debug.Logger.prototype.warning = function(msg, opt_exception) {
624 if (goog.debug.LOGGING_ENABLED) {
625 this.log(goog.debug.Logger.Level.WARNING, msg, opt_exception);
626 }
627};
628
629
630/**
631 * Logs a message at the Logger.Level.INFO level.
632 * If the logger is currently enabled for the given message level then the
633 * given message is forwarded to all the registered output Handler objects.
634 * @param {goog.debug.Loggable} msg The message to log.
635 * @param {Error=} opt_exception An exception associated with the message.
636 */
637goog.debug.Logger.prototype.info = function(msg, opt_exception) {
638 if (goog.debug.LOGGING_ENABLED) {
639 this.log(goog.debug.Logger.Level.INFO, msg, opt_exception);
640 }
641};
642
643
644/**
645 * Logs a message at the Logger.Level.CONFIG level.
646 * If the logger is currently enabled for the given message level then the
647 * given message is forwarded to all the registered output Handler objects.
648 * @param {goog.debug.Loggable} msg The message to log.
649 * @param {Error=} opt_exception An exception associated with the message.
650 */
651goog.debug.Logger.prototype.config = function(msg, opt_exception) {
652 if (goog.debug.LOGGING_ENABLED) {
653 this.log(goog.debug.Logger.Level.CONFIG, msg, opt_exception);
654 }
655};
656
657
658/**
659 * Logs a message at the Logger.Level.FINE level.
660 * If the logger is currently enabled for the given message level then the
661 * given message is forwarded to all the registered output Handler objects.
662 * @param {goog.debug.Loggable} msg The message to log.
663 * @param {Error=} opt_exception An exception associated with the message.
664 */
665goog.debug.Logger.prototype.fine = function(msg, opt_exception) {
666 if (goog.debug.LOGGING_ENABLED) {
667 this.log(goog.debug.Logger.Level.FINE, msg, opt_exception);
668 }
669};
670
671
672/**
673 * Logs a message at the Logger.Level.FINER level.
674 * If the logger is currently enabled for the given message level then the
675 * given message is forwarded to all the registered output Handler objects.
676 * @param {goog.debug.Loggable} msg The message to log.
677 * @param {Error=} opt_exception An exception associated with the message.
678 */
679goog.debug.Logger.prototype.finer = function(msg, opt_exception) {
680 if (goog.debug.LOGGING_ENABLED) {
681 this.log(goog.debug.Logger.Level.FINER, msg, opt_exception);
682 }
683};
684
685
686/**
687 * Logs a message at the Logger.Level.FINEST level.
688 * If the logger is currently enabled for the given message level then the
689 * given message is forwarded to all the registered output Handler objects.
690 * @param {goog.debug.Loggable} msg The message to log.
691 * @param {Error=} opt_exception An exception associated with the message.
692 */
693goog.debug.Logger.prototype.finest = function(msg, opt_exception) {
694 if (goog.debug.LOGGING_ENABLED) {
695 this.log(goog.debug.Logger.Level.FINEST, msg, opt_exception);
696 }
697};
698
699
700/**
701 * Logs a LogRecord. If the logger is currently enabled for the
702 * given message level then the given message is forwarded to all the
703 * registered output Handler objects.
704 * @param {goog.debug.LogRecord} logRecord A log record to log.
705 */
706goog.debug.Logger.prototype.logRecord = function(logRecord) {
707 if (goog.debug.LOGGING_ENABLED && this.isLoggable(logRecord.getLevel())) {
708 this.doLogRecord_(logRecord);
709 }
710};
711
712
713/**
714 * Logs a LogRecord.
715 * @param {goog.debug.LogRecord} logRecord A log record to log.
716 * @private
717 */
718goog.debug.Logger.prototype.doLogRecord_ = function(logRecord) {
719 goog.debug.Logger.logToProfilers('log:' + logRecord.getMessage());
720 if (goog.debug.Logger.ENABLE_HIERARCHY) {
721 var target = this;
722 while (target) {
723 target.callPublish_(logRecord);
724 target = target.getParent();
725 }
726 } else {
727 for (var i = 0, handler; handler = goog.debug.Logger.rootHandlers_[i++]; ) {
728 handler(logRecord);
729 }
730 }
731};
732
733
734/**
735 * Calls the handlers for publish.
736 * @param {goog.debug.LogRecord} logRecord The log record to publish.
737 * @private
738 */
739goog.debug.Logger.prototype.callPublish_ = function(logRecord) {
740 if (this.handlers_) {
741 for (var i = 0, handler; handler = this.handlers_[i]; i++) {
742 handler(logRecord);
743 }
744 }
745};
746
747
748/**
749 * Sets the parent of this logger. This is used for setting up the logger tree.
750 * @param {goog.debug.Logger} parent The parent logger.
751 * @private
752 */
753goog.debug.Logger.prototype.setParent_ = function(parent) {
754 this.parent_ = parent;
755};
756
757
758/**
759 * Adds a child to this logger. This is used for setting up the logger tree.
760 * @param {string} name The leaf name of the child.
761 * @param {goog.debug.Logger} logger The child logger.
762 * @private
763 */
764goog.debug.Logger.prototype.addChild_ = function(name, logger) {
765 this.getChildren()[name] = logger;
766};
767
768
769/**
770 * There is a single global LogManager object that is used to maintain a set of
771 * shared state about Loggers and log services. This is loosely based on the
772 * java class java.util.logging.LogManager.
773 * @const
774 */
775goog.debug.LogManager = {};
776
777
778/**
779 * Map of logger names to logger objects.
780 *
781 * @type {!Object<string, !goog.debug.Logger>}
782 * @private
783 */
784goog.debug.LogManager.loggers_ = {};
785
786
787/**
788 * The root logger which is the root of the logger tree.
789 * @type {goog.debug.Logger}
790 * @private
791 */
792goog.debug.LogManager.rootLogger_ = null;
793
794
795/**
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};
807
808
809/**
810 * Returns all the loggers.
811 * @return {!Object<string, !goog.debug.Logger>} Map of logger names to logger
812 * objects.
813 */
814goog.debug.LogManager.getLoggers = function() {
815 return goog.debug.LogManager.loggers_;
816};
817
818
819/**
820 * Returns the root of the logger tree namespace, the logger with the empty
821 * 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};
829
830
831/**
832 * Finds a named logger.
833 *
834 * @param {string} name A name for the logger. This should be a dot-separated
835 * name and should normally be based on the package name or class name of the
836 * 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};
844
845
846/**
847 * Creates a function that can be passed to goog.debug.catchErrors. The function
848 * 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};
860
861
862/**
863 * Creates the named logger. Will also create the parents of the named logger
864 * if they don't yet exist.
865 * @param {string} name The name of the logger.
866 * @return {!goog.debug.Logger} The named logger.
867 * @private
868 */
869goog.debug.LogManager.createLogger_ = function(name) {
870 // find parent logger
871 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);
877
878 // tell the parent about the child and the child about the parent
879 parentLogger.addChild_(leafName, logger);
880 logger.setParent_(parentLogger);
881 }
882
883 goog.debug.LogManager.loggers_[name] = logger;
884 return logger;
885};