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 } else if (Level.ERROR.equals(level) && base.isInstanceOf(message, Error)) { 315 message = message.stack; 316 } 317 var type = level.name.toLowerCase(), appenders = this.__appenders; 318 var event = { 319 level : level, 320 levelName : level.name, 321 message : message, 322 timeStamp : new Date(), 323 name : this.fullName 324 }; 325 for (var i in appenders) { 326 appenders[i].append(event); 327 } 328 } 329 }, 330 331 /** 332 * Add an appender to this logger. If this is additive then the appender is added to all subloggers. 333 * @param {comb.logging.Appender} appender the appender to add. 334 */ 335 addAppender : function(appender) { 336 if (!base.isUndefinedOrNull(appender)) { 337 var name = appender.name; 338 if (!(name in this.__appenders)) { 339 this.__appenders[name] = appender; 340 appender.level = this.level; 341 this._tree.addAppender(appender); 342 } 343 } 344 }, 345 346 /** 347 * Short cut to add a list of appenders to this Logger 348 * @param {Array<comb.logging.Appender>} appenders 349 */ 350 addAppenders : function(appenders) { 351 appenders.forEach(base.hitch(this, "addAppender")); 352 }, 353 354 /** 355 * Removes and appender from this logger. 356 * @param {String} name the name of the appender 357 */ 358 removeAppender : function(name) { 359 if (name in this.__appenders) { 360 delete this.__appenders[name]; 361 this._tree.removeAppender(name); 362 } 363 }, 364 365 /** 366 * Removes a list of appenders from this logger. 367 * 368 * @param {Array<String>} appenders a list of names of appenders to remove 369 */ 370 removeAppenders : function(appenders) { 371 appenders.forEach(this.removeAppender, this); 372 }, 373 374 /** 375 * Removes all appenders from this logger and sub loggers if this Logger is additive. 376 */ 377 removeAllAppenders : function() { 378 for (var i in this.__appenders) { 379 this.removeAppender(i); 380 } 381 }, 382 383 /** 384 * Determines if an appender is attached. 385 * 386 * @param {String} name the name of the appender. 387 */ 388 isAppenderAttached : function(name) { 389 return (name in this.__appenders); 390 }, 391 392 /** 393 * Gets an appender from this logger 394 * 395 * @param {String} name the name of the appender. 396 * 397 * @return {comb.logging.Appender|undefined} returns the appender with the specified name or 398 * undefined if it is not found. 399 */ 400 getAppender : function(name) { 401 var ret; 402 if (name in this.__appenders) { 403 ret = this.__appenders[name]; 404 } 405 return ret; 406 }, 407 408 /** 409 * @ignore 410 * */ 411 setters : { 412 413 level : function(level) { 414 level = Level.toLevel(level); 415 if (this.__additive) { 416 this.__level = level; 417 var appenders = this.__appenders; 418 for (var i in appenders) { 419 appenders[i].level = level; 420 } 421 this._tree.level = level; 422 } else { 423 this.__level = level; 424 } 425 }, 426 427 additive : function(additive) { 428 this.__additive = additive; 429 } 430 }, 431 432 /**@ignore*/ 433 getters : { 434 /**@ignore*/ 435 436 /**@ignore*/ 437 subLoggers : function() { 438 return this._tree.getSubLoggers(); 439 }, 440 441 /**@ignore*/ 442 level : function() { 443 return this.__level; 444 }, 445 446 /**@ignore*/ 447 additive : function() { 448 return this.__additive; 449 }, 450 451 isAll : function() { 452 return Level.ALL.isGreaterOrEqualToo(this.level); 453 }, 454 455 /**@ignore*/ 456 isDebug : function() { 457 return Level.DEBUG.isGreaterOrEqualToo(this.level); 458 }, 459 460 /**@ignore*/ 461 isTrace : function() { 462 return Level.TRACE.isGreaterOrEqualToo(this.level); 463 }, 464 465 /**@ignore*/ 466 isInfo : function() { 467 return Level.INFO.isGreaterOrEqualToo(this.level); 468 }, 469 470 /**@ignore*/ 471 isWarn : function() { 472 return Level.WARN.isGreaterOrEqualToo(this.level); 473 }, 474 475 /**@ignore*/ 476 isError : function() { 477 return Level.ERROR.isGreaterOrEqualToo(this.level); 478 }, 479 480 /**@ignore*/ 481 isFatal : function() { 482 return Level.FATAL.isGreaterOrEqualToo(this.level); 483 }, 484 485 /**@ignore*/ 486 isOff : function() { 487 return Level.OFF.equals(this.level); 488 }, 489 490 /**@ignore*/ 491 name : function() { 492 return this.__name; 493 }, 494 495 /**@ignore*/ 496 tree : function() { 497 return this._tree; 498 }, 499 500 /**@ignore*/ 501 appenders : function() { 502 var ret = []; 503 for (var i in this.__appenders) { 504 ret.push(this.__appenders[i]); 505 } 506 return ret; 507 }, 508 509 categories: function() { 510 return this._tree.categories; 511 } 512 } 513 }, 514 515 static : { 516 /**@lends comb.logging.Logger*/ 517 518 /** 519 * Return the root of all loggers 520 */ 521 getRootLogger : function() { 522 return rootTree.getRootLogger(); 523 }, 524 525 /** 526 * Retrieves/Creates a logger based on the name passed in 527 * 528 * @param {String} name the name of the logger 529 */ 530 getLogger : function(name) { 531 return rootTree.getLogger(name); 532 } 533 } 534 })); 535 536 var rootLogger = new Logger(""); 537 rootTree = rootLogger._tree; 538 539 540