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