      1 var define = require("../define.js"),
      2 		base = require("../base"),
      3 		Level = require("./level"),
      4 		appenders = require("./appenders"),
      5 		configurators = require("./config");
      6 var rootTree;
      7 var LoggerTree = define.define(null, {
      8 			instance : {
      9
     10 				constructor : function(root) {
     11 					this.__root = root;
     12 					this.__name = root.name;
     13 					this.__level = root.level;
     14 					this.__parent = root._parent;
     15 					this.__map = {};
     16 				},
     17
     18                 __getSubLoggers : function(){
     19                      var map = this.__map, ret = [], n;
     20 					for (var i in map) {
     21 						n = map[i];
     22 						if (n) {
     23 							ret = ret.concat(n.tree.getCurrentLoggers());
     24 						}
     25 					}
     26 					return ret;
     27                 },
     28
     29 				__getLoggers : function() {
     30 					return [this.__root].concat(this.__getSubLoggers())
     31 				},
     32
     33 				getCurrentLoggers : function() {
     34 					return this.__getLoggers();
     35 				},
     36
     37                 getSubLoggers : function() {
     38 					return this.__getSubLoggers();
     39 				},
     40
     41 				getLogger : function(name) {
     42 					var ret;
     43 					if (name) {
     44 						var parts = name.split(".");
     45 						if (parts.length) {
     46 							var category = parts.shift();
     47 							var lNode = this.__map[category];
     48 							if (!lNode) {
     49 								lNode = this.__map[category] = new Logger(category, this);
     50 								lNode.addAppenders(this.__root.appenders);
     51 							}
     52 							ret = lNode;
     53 							if (parts.length) {
     54 								//keep searching
     55 								name = parts.join(".");
     56 								ret = lNode.tree.getLogger(name);
     57 							}
     58 						}
     59 					} else {
     60 						ret = this.__root;
     61 					}
     62 					return ret;
     63 				},
     64
     65 				getRootLogger : function() {
     66 					return this.__root;
     67 				},
     68
     69 				isDisabled : function(level) {
     70 				},
     71
     72 				resetConfiguration : function() {
     73 				},
     74
     75 				/**
     76 				 * level = string|Level
     77 				 */
     78
     79 				addAppender : function(appender) {
     80 					var map = this.__map;
     81 					for (var i in map) {
     82 						map[i].addAppender(appender);
     83 					}
     84 				},
     85
     86 				removeAppender : function(name) {
     87 					var map = this.__map;
     88 					for (var i in map) {
     89 						map[i].removeAppender(name);
     90 					}
     91 				},
     92
     93 				setters : {
     94 					level : function(level) {
     95 						this.__level = level;
     96 						if (level && level instanceof Level) {
     97 							var map = this.__map;
     98 							for (var i in map) {
     99 								map[i].level = level;
    100 							}
    101
    102 						}
    103 					}
    104
    105 				},
    106
    107 				getters : {
    108 					categories : function() {
    109 						return this.getCurrentLoggers().map(function(l) {
    110 							return l.fullName;
    111 						});
    112 					},
    113
    114 					name : function() {
    115 						var ret = this.__name;
    116 						if (this.__parent) {
    117 							var pName = this.__parent.name;
    118 							if (pName) {
    119 								ret = pName + "." + ret;
    120 							}
    121 						}
    122 						return ret;
    123 					},
    124
    125 					level : function() {
    126 						return this.__level;
    127 					},
    128
    129                     additive : function(){
    130                         return this.__root.additive;
    131                     }
    132 				}
    133 			}
    134 		});
    135
    136 var comb = exports;
    137 /**@namespace logging package*/
    138 comb.logging = base.merge({
    139 			Level : Level
    140 		}, configurators);
    141 /**@namespace appenders for logging*/
    142 comb.logging.appenders = appenders;
    143
    144 var logging = comb.logging;
    145
    146 /**
    147  * @class This class is the entry point for all logging actions in comb.
    148  * <p><b>Logger should be retrieved by calling Logger.getLogger() NOT through the new keyword</b><p>
    149  * <p>
    150  *     All loggers in comb follow a heirarchy of inheritance based on a dot notation.
    151  *     <pre class="code">
    152  *                          rootLogger - ""
    153  *                                  /         \
    154  *                               "my"      "myOther"
    155  *                               /               \
    156  *                         "my.logger"       "myOther.logger"
    157  *                            /                     \
    158  *                       "my.logger.Log"        "myOther.logger.Log"
    159  *
    160  *     </pre>
    161  *     In the above Tree the rootLogger is the base for all logger. my and myOther inherit from rootLogger
    162  *     my.logger inherits from my, and myOther.logger inherits from myOther. The logs do not have to be retrieved in
    163  *     order. If I set rootLogger to ERROR level and added a console appender to it the appender and level will be
    164  *     added to all logs. However if I set my to INFO level and add a fileAppender to it the level and appender will
    165  *     only be added to logs in "my" subtree. If you set my.logger to not be additive then levels, and appenders will not
    166  *     propogate down to the rest of the tree.
    167  *
    168  * </p>
    169  *
    170  * <p>For information on levels see {@link comb.logging.Level}.</p>
    171  * <p>For information on appenders see
    172  *          <ul>
    173  *              <li>{@link comb.logging.appenders.Appender}</li>
    174  *              <li>{@link comb.logging.appenders.ConsoleAppender}</li>
    175  *              <li>{@link comb.logging.appenders.FileAppender}</li>
    176  *              <li>{@link comb.logging.appenders.JSONAppender}</li>
    177  *              <li>{@link comb.logging.appenders.RollingFileAppender}</li>
    178  *          </ul>
    179  * </p>
    180  * <p>For information on configurators see {@link comb.logging.BasicConfigurator} or {@link comb.logging.PropertyConfigurator}.</p>
    181  *
    182  * @example
    183  *
    184  * var logging = comb.logging,
    185  *     Logger = logging.Logger,
    186  *     appenders = logging.appenders,
    187  *     Level = logging.Level;
    188  *
    189  * //configure you logging environement
    190  *
    191  * var bc = logging.BasicConfigurator();
    192  * //add console appender to all loggers
    193  * bc.configure();
    194  * //add a file appender to all loggers
    195  * bc.configure(new appenders.FileAppender({file : "/var/log/myLog.log"}));
    196  *
    197  * //Retreiving a logger.
    198  * var combLogger = Logger.getLogger("comb");
    199  * var combCollectionLogger = Logger.getLogger("comb.collections");
    200  * var treeLogger = Logger.getLogger("comb.collections.Tree");
    201  *
    202  * //set my treeLogger to DEBUG Level
    203  * treeLogger.level = Level.DEBUG;
    204  * //add a JSON appender to tree logger just for fun!
    205  * treeLogger.addAppender(new appenders.JSONAppender({file : "/var/log/myTreeLogger.json"}));
    206  *
    207  * //NOW USE THEM
    208  *
    209  *
    210  * @name Logger
    211  * @memberOf comb.logging
    212  *
    213  * @property {Array<comb.logging.Logger>} subLoggers all loggers this logger is the parent of.
    214  * @property {comb.logging.Level} level the level of this Logger
    215  * @property {Boolean} additive set to false to prevent changes to this logger from propogating down.
    216  * @property {Boolean} isDebug true if this Loggers level is DEBUG
    217  * @property {Boolean} isTrace true if this Loggers level is TRACE
    218  * @property {Boolean} isInfo true if this Loggers level is INFO
    219  * @property {Boolean} isWarn true if this Loggers level is WARN
    220  * @property {Boolean} isError true if this Loggers level is ERROR
    221  * @property {Boolean} isFatal true if this Loggers level is FATAL
    222  * @property {Boolean} isOff true if this Loggers level is OFF
    223  * @property {String} name the name of this logger this <b>does not</b> include the dot notated name
    224  * @property {String} fullName the full path name of this Logger.
    225  * @property {comb.logging.appenders.Appender} appenders list of appenders this logger currently contains.
    226  */
    227 var Logger = (logging.Logger = define.define(null, {
    228
    229 			instance: {
    230 				/**@lends comb.logging.Logger.prototype*/
    231
    232 				constructor : function(name, parent) {
    233 					this.__additive = true;
    234 					this.__name = name;
    235 					this._parent = parent;
    236 					this._tree = new LoggerTree(this);
    237 					this.fullName = this._tree.name;
    238 					if (!parent || !parent.additive) {
    239 						this.level = Level.ALL;
    240 					} else {
    241 						this.level = parent.level;
    242 					}
    243 					this.__appenders = {};
    244 				},
    245
    246 				/**
    247 				 * Log an info level message
    248 				 *
    249 				 * @param {String} message the message to log.
    250 				 */
    251 				info : function(message) {
    252 					this.log(Level.INFO, message);
    253 				},
    254
    255 				/**
    256 				 * Log an debug level message
    257 				 *
    258 				 * @param {String} message the message to log.
    259 				 */
    260 				debug : function(message) {
    261 					this.log(Level.DEBUG, message);
    262 				},
    263
    264 				/**
    265 				 * Log an error level message
    266 				 *
    267 				 * @param {String} message the message to log.
    268 				 */
    269 				error : function(message) {
    270 					this.log(Level.ERROR, message);
    271 				},
    272
    273 				/**
    274 				 * Log an warn level message
    275 				 *
    276 				 * @param {String} message the message to log.
    277 				 */
    278 				warn : function(message) {
    279 					this.log(Level.WARN, message);
    280 				},
    281
    282 				/**
    283 				 * Log an trace level message
    284 				 *
    285 				 * @param {String} message the message to log.
    286 				 */
    287 				trace : function(message) {
    288 					this.log(Level.TRACE, message);
    289 				},
    290
    291 				/**
    292 				 * Log an fatal level message
    293 				 *
    294 				 * @param {String} message the message to log.
    295 				 */
    296 				fatal : function(message) {
    297 					this.log(Level.FATAL, message);
    298 				},
    299
    300 				/**
    301 				 * Log a message
    302 				 *
    303 				 * @param {comb.logging.Level} level the level the message is
    304 				 * @param {String} message the message to log.
    305 				 */
    306 				log : function(level, message) {
    307 					if (level.isGreaterOrEqualToo(this.level)) {
    308 						if (Level.TRACE.equals(level)) {
    309 							var err = new Error;
    310 							err.name = "Trace";
    311 							err.message = message || '';
    312 							Error.captureStackTrace(err, arguments.callee);
    313 							message = err.stack;
    314 						}
    315 						var type = level.name.toLowerCase(), appenders = this.__appenders;
    316 						var event = {
    317 							level : level,
    318 							levelName : level.name,
    319 							message : message,
    320 							timeStamp : new Date(),
    321 							name : this.fullName
    322 						};
    323 						for (var i in appenders) {
    324 							appenders[i].append(event);
    325 						}
    326 					}
    327 				},
    328
    329 				/**
    330 				 * Add an appender to this logger. If this is additive then the appender is added to all subloggers.
    331 				 * @param {comb.logging.Appender} appender the appender to add.
    332 				 */
    333 				addAppender : function(appender) {
    334 					if (appender) {
    335 						var name = appender.name;
    336 						if (!(name in this.__appenders)) {
    337 							this.__appenders[name] = appender;
    338 							appender.level = this.level;
    339 							this._tree.addAppender(appender);
    340 						}
    341 					}
    342 				},
    343
    344 				/**
    345 				 * Short cut to add a list of appenders to this Logger
    346 				 * @param {Array<comb.logging.Appender>} appenders
    347 				 */
    348 				addAppenders : function(appenders) {
    349 					appenders.forEach(base.hitch(this, "addAppender"));
    350 				},
    351
    352 				/**
    353 				 * Removes and appender from this logger.
    354 				 * @param {String} name the name of the appender
    355 				 */
    356 				removeAppender : function(name) {
    357 					if (name in this.__appenders) {
    358 						delete this.__appenders[name];
    359 						this._tree.removeAppender(name);
    360 					}
    361 				},
    362
    363 				/**
    364 				 * Removes a list of appenders from this logger.
    365 				 *
    366 				 * @param {Array<String>} appenders a list of names of appenders to remove
    367 				 */
    368 				removeAppenders : function(appenders) {
    369 					appenders.forEach(this.removeAppender, this);
    370 				},
    371
    372 				/**
    373 				 * Removes all appenders from this logger and sub loggers if this Logger is additive.
    374 				 */
    375 				removeAllAppenders : function() {
    376 					for (var i in this.__appenders) {
    377 						this.removeAppender(i);
    378 					}
    379 				},
    380
    381 				/**
    382 				 * Determines if an appender is attached.
    383 				 *
    384 				 * @param {String} name the name of the appender.
    385 				 */
    386 				isAppenderAttached : function(name) {
    387 					return (name in this.__appenders);
    388 				},
    389
    390                 /**
    391 				 * Gets an appender from this logger
    392 				 *
    393 				 * @param {String} name the name of the appender.
    394                  *
    395                  * @return {comb.logging.Appender|undefined} returns the appender with the specified name or
    396                  *                                          undefined if it is not found.
    397 				 */
    398 				getAppender : function(name) {
    399                     var ret;
    400 					if(name in this.__appenders){
    401                         ret = this.__appenders[name];
    402                     }
    403                     return ret;
    404 				},
    405
    406 				/**
    407                  * @ignore
    408                  * */
    409 				setters : {
    410
    411 					level : function(level) {
    412                         level = Level.toLevel(level);
    413 						if (this.__additive) {
    414 							this.__level = level;
    415 							var appenders = this.__appenders;
    416 							for (var i in appenders) {
    417 								appenders[i].level = level;
    418 							}
    419 							this._tree.level = level;
    420 						} else {
    421 							this.__level = level;
    422 						}
    423 					},
    424
    425 					additive : function(additive) {
    426 						this.__additive = additive;
    427 					}
    428 				},
    429
    430 				/**@ignore*/
    431 				getters : {
    432 					/**@ignore*/
    433
    434 							/**@ignore*/
    435 					subLoggers : function() {
    436 						return this._tree.getSubLoggers();
    437 					},
    438
    439 					/**@ignore*/
    440 					level : function() {
    441 						return this.__level;
    442 					},
    443
    444 					/**@ignore*/
    445 					additive : function() {
    446 						return this.__additive;
    447 					},
    448
    449                     isAll : function(){
    450                          	return Level.ALL.isGreaterOrEqualToo(this.level);
    451                     },
    452
    453 					/**@ignore*/
    454 					isDebug : function() {
    455 						return Level.DEBUG.isGreaterOrEqualToo(this.level);
    456 					},
    457
    458 					/**@ignore*/
    459 					isTrace : function() {
    460 						return Level.TRACE.isGreaterOrEqualToo(this.level);
    461 					},
    462
    463 					/**@ignore*/
    464 					isInfo : function() {
    465 						return Level.INFO.isGreaterOrEqualToo(this.level);
    466 					},
    467
    468 					/**@ignore*/
    469 					isWarn : function() {
    470 						return Level.WARN.isGreaterOrEqualToo(this.level);
    471 					},
    472
    473 					/**@ignore*/
    474 					isError : function() {
    475 						return Level.ERROR.isGreaterOrEqualToo(this.level);
    476 					},
    477
    478 					/**@ignore*/
    479 					isFatal : function() {
    480 						return Level.FATAL.isGreaterOrEqualToo(this.level);
    481 					},
    482
    483 					/**@ignore*/
    484 					isOff : function() {
    485 						return Level.OFF.equals(this.level);
    486 					},
    487
    488 					/**@ignore*/
    489 					name : function() {
    490 						return this.__name;
    491 					},
    492
    493 					/**@ignore*/
    494 					tree : function() {
    495 						return this._tree;
    496 					},
    497
    498 					/**@ignore*/
    499 					appenders : function() {
    500 						var ret = [];
    501 						for (var i in this.__appenders) {
    502 							ret.push(this.__appenders[i]);
    503 						}
    504 						return ret;
    505 					},
    506
    507                     categories: function(){
    508                         return this._tree.categories;
    509                     }
    510 				}
    511 			},
    512
    513 			static : {
    514 				/**@lends comb.logging.Logger*/
    515
    516 				/**
    517 				 * Return the root of all loggers
    518 				 */
    519 				getRootLogger : function() {
    520 					return rootTree.getRootLogger();
    521 				},
    522
    523 				/**
    524 				 * Retrieves/Creates a logger based on the name passed in
    525 				 *
    526 				 * @param {String} name the name of the logger
    527 				 */
    528 				getLogger : function(name) {
    529 					return rootTree.getLogger(name);
    530 				}
    531 			}
    532 		}));
    533
    534 var rootLogger = new Logger("");
    535 rootTree = rootLogger._tree;
    536
    537
    538