Saturday, 28 September 2013

"Comb" Library: Logging (2 of 2)

Hi! Before continuing note this is the second part of my "Comb" logging guide. For part one see: "Comb" Library: Logging. Else, on we go.

In this part let's cover the configuration of the logging system by calling the logging configuration function comb.logger.configure that will state what level should be stored/outputted to where.

Before this we need to know about Appenders. Appenders are the end points that can be attached to logers.

Multiple appenders are already included as part of the Comb Library
  • FileAppender - log it to a file
  • RollingFileAppender - log it to a file up to a customizable size then create a new one.
  • JSONAppender - write it out as JSON to a file.
  • ConsoleAppender- log it to the consol

To declare a appender and its target, it would look something like this.
var myLogger = comb.logger("my.logger")
    .addAppender("ConsoleAppender")
    .addAppender("FileAppender", {file:'/var/log/my.log'})
    .addAppender("RollingFileAppender", {file:'/var/log/myRolling.log'})
    .addAppender("JSONAppender", {file:'/var/log/myJson.log'});

Level class used to describe logging levels. The levels determine what types of events are logged to the appenders for example the if Level.ALL is used then all event will be logged, however if Level.INFO was used then ONLY INFO, WARN, ERROR, and FATAL events will be logged. To turn off logging for a logger use Level.OFF.
comb.logger.configure();
//the loggers you create now will have a ConsoleAppender
OR
comb.logger.configure(comb.logger.appender("FileAppender", {file : '/var/log/my.log'}));
//loggers will have a FileAppender

The Cool part(Nerd time ;) Let's create a configuration file.
We configure by passing a block JSON to the "configure" function.

Configuration object layout:
  • "name space"(object attribute) -> Object
    • level(object attribute) -> String
    • appenders(Array) -> objects
      • name -> String
      • level -> String
      • type -> String
      • file -> String
      • pattern -> String
      • overwrite -> String

Example from the comb site:
    comb.logger.configure({
        "my.logger": {
            level: "INFO",
            appenders: [{
                //default file appender
                type: "FileAppender",
                file: "/var/log/myApp.log",
            }, {
                //default JSON appender
                type: "JSONAppender",
                file: "/var/log/myApp.json",
            }, {
                type: "FileAppender",
                //override default patter
                pattern: "{[EEEE, MMMM dd, yyyy h:m a]timeStamp} {[5]level} {[- 5]levelName} {[-20]name} : {message}",
                //location of my log file
                file: "/var/log/myApp-errors.log",
                //override name so it will get added to the log
                name: "errorFileAppender",
                //overwrite each time
                overwrite: true,
                //explicity set the appender to only accept errors
                level: "ERROR"
            }, {
                type: "JSONAppender",
                file: "/var/log/myApp-error.json",
                //explicity set the appender to only accept errors
                level: "ERROR"
            }]
        }
    })

You can also log directly to levels with
    var logger = comb.logger("logger");
    logger.log("info", "my message");
    // or if it is one of the default types
    logger.info("my message");

Here the list of pre-supported functions
    logger.debug("debug message"); logger.trace("trace message"); logger.info("info message"); logger.warn("warn message"); logger.error("error message"); logger.fatal("fatal message");
... continue reading!

Friday, 27 September 2013

"Comb" Library: Logging (1 of 2)

Continuing with my overview of the comb library Lets taking a look at the logging functions available.

logging is critical in your applications, not just for errors but in order to get a good understanding of how your application is operating in the wild/production.

So what am I going to cover in the post.. well let see:

  • Logger inheritance through name spaces
  • Predefined level level definition along with the ability to define your own.
Logger inheritance through name spaces.. sample code anyone?

Lets load the comb library
var comb = require('comb'); //load the comb lib

Lets load a set of different elements for logging in different aspects
var logger_sys = comb.logger("sys");
var logger_user = comb.logger("user");
var logger_sys_logger = comb.logger("sys.logger");
var logger_user_logger = comb.logger("user.logger");

Note that the "." dot denotes the separation of "name space" levels

Next here's a simple function just to print out the current level attribute for each of our elements for logging.
function print(){
 console.log("sys:"+logger_sys.level.name);
 console.log("user:"+logger_user.level.name);
 console.log("sysL:"+logger_sys_logger.level.name);
 console.log("userL:"+logger_user_logger.level.name);
 console.log();//lets skip a line for readability
}

let's set a description for each of the logging levels
console.log(">> lets set what the defalts level looks like");
print();

console.log(">> lets set sys and its child to 'DEBUG'");
logger_sys.level = 'DEBUG';
print();


console.log(">> lets set user and its child to 'INFO'");
logger_user.level = 'INFO';
print();

console.log(">> Now we will ONLY set sys.logger to 'WARN'");
logger_sys_logger.level = 'WARN';
print();

examples of inheritance within logging
console.log('>> If will create a sub logger');
console.log('>> It will inherit the level from its parent');
console.log(comb.logger('sys.logger.log').level.name);

So what is the point in this??

Ok, let's take you have "INFO" and "ERROR" levels(for a full list of predefined logging levels see comb.logging.Level) So we can call a logging instance something inspired like "mypack.myclass.note" and set the level to INFO and another with "mypack.myclass.problem" to "ERROR".

Something important to note is that if you used the same "name space" name in the same or a different file, it will return the same global instants regardless.


Continue to part 2: Configurable with files OR programatically
... continue reading!