* added support of passing promises objects which will be resolved with
pre-connected db object in options.db;
* fixed issue when events logged sometime between authorizeDb and
processOpQuery calls may be lost;
* renamed default log collection to 'log' because it makes more sense than
'logs' ('log' is a list of messages already, plural form would imply
multiple of such lists);
* this.mainDb renamed to this.logDb;
* this._opQuery renamed to this._opQueue;
* added test to promises support (bluebird added to devDependencies as A+ promises implementation).
This commit is contained in:
Yurij Mikhalevich 2015-03-23 22:13:24 +03:00
Родитель 7a7b98ed25
Коммит ccf69f6cc7
4 изменённых файлов: 81 добавлений и 44 удалений

Просмотреть файл

@ -34,11 +34,12 @@ The MongoDB transport takes the following options. 'db' is required:
'info'.
* __silent:__ Boolean flag indicating whether to suppress output, defaults to
false.
* __db:__ MongoDB connection uri or preconnected db object.
* __db:__ MongoDB connection uri, pre-connected db object or promise object
which will be resolved with pre-connected db object.
* __options:__ MongoDB connection parameters (optional, defaults to
`{db: {native_parser: true}, server: {poolSize: 2, socketOptions: {autoReconnect: true}}}`).
* __collection__: The name of the collection you want to store log messages in,
defaults to 'logs'.
defaults to 'log'.
* __storeHost:__ Boolean indicating if you want to store machine hostname in
logs entry, if set to true it populates MongoDB entry with 'hostname' field,
which stores os.hostname() value.
@ -74,11 +75,21 @@ settled by mongodb, defaults to `false`.
## Changelog
### Brief 1.1.0 changelog
* added support of passing promises objects which will be resolved with
pre-connected db object in options.db;
* fixed issue when events logged sometime between authorizeDb and
processOpQuery calls may be lost;
* renamed default log collection to 'log' because it makes more sense than
'logs' ('log' is a list of messages already, plural form would imply
multiple of such lists).
### Brief 1.0.0 changelog
* migrated to mongodb 2.x driver;
* changed configuration format to MongoDB uri string;
* added support of passing preconnected db object instead of MongoDB uri string;
* added support of passing pre-connected db object instead of MongoDB uri string;
* added support of passing MongoDB connection parameters in options property;
* added support of replica sets through new options and db properties;
* migrated to [Semantic Versioning](http://semver.org/) in package versions names;

Просмотреть файл

@ -63,7 +63,7 @@ var MongoDB = exports.MongoDB = function(options) {
}
};
}
this.collection = (options.collection || 'logs');
this.collection = (options.collection || 'log');
this.level = (options.level || 'info');
this.silent = options.silent;
this.username = options.username;
@ -77,47 +77,55 @@ var MongoDB = exports.MongoDB = function(options) {
this.hostname = os.hostname();
}
this._opQuery = [];
this._opQueue = [];
var self = this;
function processOpQuery() {
self._opQuery.forEach(function(operation) {
self[operation.method].apply(self, operation.args);
function setupDatabaseAndEmptyQueue(db) {
authorizeDb(db, function(err, db) {
createCollection(db, function(err, db) {
self.logDb = db;
processOpQueue();
});
});
delete self._opQuery;
}
function createCollection(cb) {
function processOpQueue() {
self._opQueue.forEach(function(operation) {
self[operation.method].apply(self, operation.args);
});
delete self._opQueue;
}
function createCollection(db, cb) {
var opts = {};
if (self.capped) {
opts = {capped: true, size: self.cappedSize};
}
self.mainDb.createCollection(self.collection, opts, function() {
cb(null);
db.createCollection(self.collection, opts, function() {
cb(null, db);
});
}
function authorizeDb(cb) {
function authorizeDb(db, cb) {
if (self.username && self.password) {
self.mainDb.authenticate(self.username, self.password,
db.authenticate(self.username, self.password,
function(err, result) {
if (err) {
console.error('winston-mongodb: error initialising logger', err);
self.mainDb.close();
db.close();
return;
}
if (!result) {
console.error('winston-mongodb: invalid username or password');
self.mainDb.close();
db.close();
return;
}
cb(null);
cb(null, db);
}
);
}
cb(null);
cb(null, db);
}
if ('string' === typeof this.db) {
@ -126,16 +134,17 @@ var MongoDB = exports.MongoDB = function(options) {
console.error('winston-mongodb: error initialising logger', err);
return;
}
self.mainDb = db;
authorizeDb(function() {
createCollection(processOpQuery);
});
setupDatabaseAndEmptyQueue(db);
});
} else if ('function' === typeof this.db.then) {
this.db.then(function(db) {
setupDatabaseAndEmptyQueue(db);
}, function(err) {
console.error(
'winston-mongodb: error initialising logger from promise', err);
});
} else {
this.mainDb = this.db;
authorizeDb(function() {
createCollection(processOpQuery);
});
setupDatabaseAndEmptyQueue(this.db);
}
};
@ -161,8 +170,8 @@ winston.transports.MongoDB = MongoDB;
* @param {Function} callback Continuation to respond to when complete.
*/
MongoDB.prototype.log = function(level, msg, opt_meta, callback) {
if (!this.mainDb) {
this._opQuery.push({
if (!this.logDb) {
this._opQueue.push({
method: 'log',
args: arguments
});
@ -186,7 +195,7 @@ MongoDB.prototype.log = function(level, msg, opt_meta, callback) {
callback(err, null);
}
self.mainDb.collection(self.collection, function(err, col) {
self.logDb.collection(self.collection, function(err, col) {
if (err) {
onError(err);
return;
@ -225,8 +234,8 @@ MongoDB.prototype.log = function(level, msg, opt_meta, callback) {
* @return {*}
*/
MongoDB.prototype.query = function(opt_options, callback) {
if (!this.mainDb) {
this._opQuery.push({
if (!this.logDb) {
this._opQueue.push({
method: 'query',
args: arguments
});
@ -257,7 +266,7 @@ MongoDB.prototype.query = function(opt_options, callback) {
opt.fields = options.fields;
}
this.mainDb.collection(this.collection, function(err, col) {
this.logDb.collection(this.collection, function(err, col) {
if (err) {
callback(err);
return;
@ -293,8 +302,8 @@ MongoDB.prototype.stream = function(options, stream) {
var self = this;
var start = options.start;
if (!this.mainDb) {
this._opQuery.push({
if (!this.logDb) {
this._opQueue.push({
method: 'stream',
args: [options, stream]
});
@ -310,7 +319,7 @@ MongoDB.prototype.stream = function(options, stream) {
}
if (start != null) {
this.mainDb.collection(this.collection, function(err, col) {
this.logDb.collection(this.collection, function(err, col) {
if (err) {
stream.emit('error', err);
return;
@ -334,7 +343,7 @@ MongoDB.prototype.stream = function(options, stream) {
return stream;
}
this.mainDb.collection(this.collection, function(err, col) {
this.logDb.collection(this.collection, function(err, col) {
if (err) {
stream.emit('error', err);
return;
@ -387,8 +396,8 @@ MongoDB.prototype.streamPoll = function(options, stream) {
var start = options.start;
var last;
if (!this.mainDb) {
this._opQuery.push({
if (!this.logDb) {
this._opQueue.push({
method: 'streamPoll',
args: [options, stream]
});
@ -408,7 +417,7 @@ MongoDB.prototype.streamPoll = function(options, stream) {
};
(function check() {
self.mainDb.collection(self.collection, function(err, col) {
self.logDb.collection(self.collection, function(err, col) {
if (err) {
stream.emit('error', err);
return;

Просмотреть файл

@ -1,7 +1,7 @@
{
"name": "winston-mongodb",
"license": "MIT",
"version": "1.0.1",
"version": "1.1.0",
"description": "A MongoDB transport for winston",
"author": "Charlie Robbins <charlie.robbins@gmail.com>",
"contributors": [
@ -19,7 +19,8 @@
},
"devDependencies": {
"winston": "0.9.x",
"vows": "0.8.x"
"vows": "0.8.x",
"bluebird": "2.9.x"
},
"main": "./lib/winston-mongodb",
"scripts": { "test": "vows test/*-test.js --spec" }

Просмотреть файл

@ -7,6 +7,8 @@
*/
var vows = require('vows');
var mongodb = require('mongodb');
var Promise = require('bluebird');
var transport = require('winston/test/transports/transport');
var MongoDB = require('../lib/winston-mongodb').MongoDB;
@ -14,10 +16,24 @@ vows.describe('winston-mongodb').addBatch({
'An instance of the MongoDB Transport': transport(MongoDB, {
db: 'mongodb://localhost/winston'
}),
'And instance of the MongoDB Transport on capped collection':
'An instance of the MongoDB Transport on capped collection':
transport(MongoDB, {
db: 'mongodb://localhost/winston',
capped: true,
collection: 'cappedLogs'
collection: 'cappedLog'
})
}).addBatch({
'An instance of the MongoDB Transport with promise':
transport(MongoDB, {
db: new Promise(function(resolve, reject) {
mongodb.MongoClient.connect('mongodb://localhost/winston',
function(err, db) {
if (err) {
reject(err);
} else {
resolve(db);
}
});
})
})
}).export(module);