/*1* log.js: Default logging plugin which attachs winston to App instances2*3* (C) 2011, Nodejitsu Inc.4* MIT LICENSE5*6*/78var winston = require('winston'),9common = require('../common');1011var log = exports;1213//14// ### Setup default state for the exceptions plugin15//16log.name = 'log';17log.ignore = ['broadway'];1819//20// ### function attach (options)21// #### @options {Object} Options for this plugin22// Extends `this` (the application) with logging functionality from `winston`.23//24log.attach = function (options) {25options = options || {};2627var app = this,28namespaces,29logAll;3031if (this.config) {32//33// Merge options with any pre-existing application config.34//35options = common.mixin({}, options, this.config.get('log') || {});36}3738//39// Setup namespaces and then remove them from40// `options` so they are not caught by `winston`.41//42namespaces = options.namespaces || {};43delete options.namespaces;4445logAll = options.logAll || false;46if (options.logAll) {47delete options.logAll;48}4950//51// Hoist up relelvant logging functions onto the app52// if requested.53//54this.log = new winston.Container(options);55this.log.namespaces = namespaces;56this.log.get('default').extend(this.log);5758//59// Set the default console loglevel to options.level60//61this.log.get('default').transports.console.level = options.level || 'info';6263Object.defineProperty(this.log, 'logAll', {64get: function () {65return this._logAll;66},67set: function (val) {68if (val === this._logAll) {69//70// If the value is identical return71//72return;73}7475if (val) {76app.onAny(log.logEvent);77app.off(['log'], log.logEvent);78app.off(['log', '*'], log.logEvent);79app.off(['log', '*', '*'], log.logEvent);80}81else {82app.offAny(log.logEvent);83app.on(['log'], log.logEvent);84app.on(['log', '*'], log.logEvent);85app.on(['log', '*', '*'], log.logEvent);86}8788this._logAll = val;89}90});9192//93// Listen to relevant `app` events and94// log them appropriately.95//96this.log.logAll = logAll;9798//99// Add any namespaced containers to this App instance.100//101Object.keys(this.log.namespaces).forEach(function (namespace) {102app.log.add(app.log.namespaces[namespace]);103});104};105106//107// ### function logEvent ([level], msg, meta)108// #### @msg {string} Message to log109// #### @meta {Object} **Optional** Metadata to log110// Logs the specified `msg` and `meta` according to111// the following conditions:112//113// #### `log` events114// 1. `log` - Logs to the default logger and level.115// 2. `log::[level]` - Logs to the default logger.116// 3. `log::[level]::[namespace]` - Logs to a namespaced logger.117//118// ### `[namespaced]` events119// If `app.log.logAll` is set, then find a logger at `namespace`,120// otherwise the default logger is used.121//122// 1. `[namespace]::**(level, msg, meta)` - Logs the event as the123// message to the logger for the specified namespace and level.124// 2. `[namespace]::[level]::**(msg, meta)` - Logs the event and125// the message to the logger for the specified namespace and level.126//127log.logEvent = function (/* level, msg, meta */) {128var parts = Array.isArray(this.event) ? this.event : this.event.split(this.delimiter),129ev = parts[0],130namespace,131logger,132level,133meta,134msg;135136if (log.ignore.indexOf(ev) !== -1) {137return;138}139140//141// Determine the `namespace` to log the event to142//143if (ev === 'log') {144namespace = parts[2] || 'default';145logger = this.log.get('default');146}147else if (this.log.logAll) {148namespace = this.log.namespaces[ev] ? this.log.namespaces[ev] : 'default';149logger = this.log.get(namespace);150}151else {152return;153}154155//156// Parse arguments now that we have the logger.157//158Array.prototype.slice.call(arguments).forEach(function (a) {159switch (typeof a) {160case 'object': {161meta = a;162break;163}164case 'string': {165if (logger[a]) {166level = a;167}168else {169msg = a;170}171}172}173});174175if (ev === 'log') {176level = parts[1] || level || 'info';177}178else if (this.log.logAll) {179if (logger[parts[1]]) {180level = parts[1];181parts.splice(1, 1);182}183}184185if (level in logger.levels === false) {186level = 'info';187}188189parts = parts.join(this.delimiter);190meta = meta || {};191meta.event = parts;192msg = msg || parts;193logger.log(level, msg, meta);194this.emit(['broadway', 'logged'], level, msg, meta);195};196197198