Loggers have a log level that is compared against log messages. All messages that are of a lower level than the Logger are ignored. This is useful to reduce less important messages in production deployments.

var intel =require('intel');

intel.setLevel(intel.WARN);

intel.warn('i made it!');

intel.debug('nobody loves me');

All levels by order: (each level has a corresponding method on a Logger)

intel.TRACE // intel.trace()

intel.VERBOSE // intel.verbose()

intel.DEBUG // intel.debug()

intel.INFO // intel.info()

intel.WARN // intel.warn()

intel.ERROR // intel.error()

intel.CRITICAL // intel.critical()

Useful levels that don't have accompanying logger methods are intel.NONE and intel.ALL.

Using named loggers gives you a lot of power in intel. First, the logger name can be included in the log message, so you can more easily understand where log messages are happening inside your application.

var log =require('intel').getLogger('foo.bar.baz');

log.setLevel(log.INFO).warn('baz reporting in');

The names are used to build an hierarchy of loggers. Child loggers can inherit their parents' handlers and log level.

Any time you pass an exception (an Error!) to a log method, the stack
will be included in the output. In most cases, it will be appended at
the end of the message. If the format is %O, meaning JSON output, a
stack property will be included.

intel.error('ermahgawd',newError('boom'));

Loggers can also handle uncaughtException, passing it to its handlers,
and optionally exiting afterwards.

var logger = intel.getLogger('medbay');

logger.handleExceptions(exitOnError);

Pass a boolean for exitOnError. Default is true if no value is passed.

Loggers build a message and try to pass the message to all of it's handlers and to it's parent. Handlers determine exactly what to do with that message, whether it's sending it to console, to a file, over a socket, or nothing at all.

You can already plug together handlers and loggers, with varying levels, to get powerful filtering of messages. However, sometimes you really need to filter on a specific detail on a message. You can add these filters to a Handler or Logger.

intel.addFilter(newintel.Filter(/^foo/g));

intel.addFilter(newintel.Filter('patrol.db'));

intel.addFilter(newintel.Filter(filterFunction));

Filters come in 3 forms:

string - pass a string to filter based on Logger name. So, Filter('foo.bar') will allow messages from foo.bar, foo.bar.baz, but not foo.barstool.

regexp - pass a RegExp to filter based on the text content of the log message. So, Filter(/^foo/g) will allow messages like log.info('foo bar') but not log.info('bar baz foo');

function - pass a function that receives a LogRecord object, and returns true if the record meets the filter.

A Formatter is used by a Handler to format the message before being sent out. An useful example is wanting logs that go to the Console to be terse and easy to read, but messages sent to a File to include a lot more detail.

format: A format string that will be used with printf. Default: %(message)s

datefmt: A string to be used to format the date. Will replace instances of %(date)s in the format string. Default: %Y-%m-%d %H:%M-%S

strip: A boolean for whether to strip ANSI escape codes from the message and args. Default: false

colorize: A boolean for whether to colorize the levelname. Disabled when strip is used. Default: false

The basicConfig is useful if you don't wish to do any complicated configuration (no way, really?). It's a quick way to setup the root default logger in one function call. Note that if you don't setup any handlers before logging, basicConfig will be called to setup the default logger.

intel.basicConfig({

'file':'/path/to/file.log',// file and stream are exclusive. only pass 1

'stream': stream,

'format':'%(message)s',

'level': intel.INFO

});

The options passed to basicConfig can include:

file - filename to log

stream - any WritableStream

format - a format string

level - the log level

You cannot pass a file and stream to basicConfig. If you don't provide either, a Console handler will be used. If you wish to specify multiple or different handlers, take a look at the more comprehensive config.

We set up 2 handlers, one Console with a level of VERBOSE and a simple format, and one File with a level of WARN and a detailed format. We then set up a few options on loggers. Not all loggers need to be defined here, as child loggers will inherit from their parents. So, the root logger that we'll use in this application is patrol. It will send all messages that are INFO and greater to the the terminal. We also specifically want database errors to be logged to the our log file. And, there's a logger for express? What's that all about? See the intel.console section.

Config also accepts JSON, simply put a require path in any class properties.

So, a problem with logging libraries is trying to get them to work with 3rd party modules. Many libraries may benefit from logging when certain things occur, but can't really pick a logging library, since that sort of choice should be up to the app developer. The only real options they have are to not log anything, or to use console.log. So really, they should console.log() all the the things, and intel can work just fine with that.

Intel has the ability to override the global console, such that calling any of it's methods will send it through a Logger. This means that messages from other libraries can be sent to your log files, or through an email, or whatever. Even better, intel will automatically derive a name for the each module that access console.log (or info, warn, dir, trace, etc). In the config example, we set up rules for patrol.node_modules.express. If express were to log things as it handled requests, they would all derive a name that was a child of our logger. So, in case it's chatty, we're only interesting in WARN or greater messages, and send those to a log file.

It tries its darndest to best guess a name, by comparing the relative paths from the root and the module accessing console. By default, the root is equal to the dirname of the module where you call intel.console().

The debug option for intel.console(), huh? Yea, so many libraries use the debug() library to handle their internal logging needs. It works by not outputing any logs unless you opt-in with an environment variable. In many case, it would make sense to just leave this off, to keep the noise down. However, you can use this option to turn on a libraries logging, and route it into properly named loggers. Since the debug module checks process.env at require time, you will need to use this option firstmost, before requiring anything else that may require debug.