      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