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