flatiron/winston — pull request #179 by ericmedem (2012-09-22 13:36:42+00:00)
Title: Transport sharing does not behave properly

Winston default transports overrides shared transports in latest release:

Example attempting to force all loggers to log to mongodb:

var MongoDB = require('winston-mongodb').MongoDB;

var mongoOptions = {
'level':'debug',
'host':'localhost',
'port':'27017',
'db':'logging',
'collection':'logs',
}

winston.loggers.options.transports = [
new winston.transports.MongoDB(mongoOptions)
]

var logger = winston.loggers.get('web',{
file:{
filename: 'web.log',
json:true
}
});

I expect, given the order of operations, that I would end up with two transports: 'mongodb', 'file'. This is not the case:

Object.keys(logger.transports).forEach(function(name){
console.log(name);
});

gives

console
file

This is due to a bug in the Container class. My default shared transports are getting overridden by the "default.transports" object created by Contrainer's constructor:

Container.prototype.get = Container.prototype.add = function (id, options) {
if (!this.loggers[id]) {
options = common.clone(options || this.options || this.default);
// this.options.transports and this.default.transports will never be taken if
// an options object is provided.
options.transports = options.transports || [];

if (options.transports.length === 0 && (!options || !options['console'])) {
options.transports.push(this.default.transports[0]);
}
...
// finish providing logger
...
}

I would recommend adding this easy fix:

Container.prototype.get = Container.prototype.add = function (id, options) {
if (!this.loggers[id]) {
options = common.clone(options || this.options || this.default);
// here is my fix
options.transports = options.transports || this.options.transports || [];

if (options.transports.length === 0 && (!options || !options['console'])) {
options.transports.push(this.default.transports[0]);
}
...
// finish providing logger
...
}