Version 1.1.0 released:
* 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:
Родитель
7a7b98ed25
Коммит
ccf69f6cc7
17
README.md
17
README.md
|
@ -34,11 +34,12 @@ The MongoDB transport takes the following options. 'db' is required:
|
||||||
'info'.
|
'info'.
|
||||||
* __silent:__ Boolean flag indicating whether to suppress output, defaults to
|
* __silent:__ Boolean flag indicating whether to suppress output, defaults to
|
||||||
false.
|
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
|
* __options:__ MongoDB connection parameters (optional, defaults to
|
||||||
`{db: {native_parser: true}, server: {poolSize: 2, socketOptions: {autoReconnect: true}}}`).
|
`{db: {native_parser: true}, server: {poolSize: 2, socketOptions: {autoReconnect: true}}}`).
|
||||||
* __collection__: The name of the collection you want to store log messages in,
|
* __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
|
* __storeHost:__ Boolean indicating if you want to store machine hostname in
|
||||||
logs entry, if set to true it populates MongoDB entry with 'hostname' field,
|
logs entry, if set to true it populates MongoDB entry with 'hostname' field,
|
||||||
which stores os.hostname() value.
|
which stores os.hostname() value.
|
||||||
|
@ -74,11 +75,21 @@ settled by mongodb, defaults to `false`.
|
||||||
|
|
||||||
## Changelog
|
## 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
|
### Brief 1.0.0 changelog
|
||||||
|
|
||||||
* migrated to mongodb 2.x driver;
|
* migrated to mongodb 2.x driver;
|
||||||
* changed configuration format to MongoDB uri string;
|
* 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 passing MongoDB connection parameters in options property;
|
||||||
* added support of replica sets through new options and db properties;
|
* added support of replica sets through new options and db properties;
|
||||||
* migrated to [Semantic Versioning](http://semver.org/) in package versions names;
|
* 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.level = (options.level || 'info');
|
||||||
this.silent = options.silent;
|
this.silent = options.silent;
|
||||||
this.username = options.username;
|
this.username = options.username;
|
||||||
|
@ -77,47 +77,55 @@ var MongoDB = exports.MongoDB = function(options) {
|
||||||
this.hostname = os.hostname();
|
this.hostname = os.hostname();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this._opQueue = [];
|
||||||
this._opQuery = [];
|
|
||||||
|
|
||||||
var self = this;
|
var self = this;
|
||||||
|
|
||||||
function processOpQuery() {
|
function setupDatabaseAndEmptyQueue(db) {
|
||||||
self._opQuery.forEach(function(operation) {
|
authorizeDb(db, function(err, db) {
|
||||||
self[operation.method].apply(self, operation.args);
|
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 = {};
|
var opts = {};
|
||||||
if (self.capped) {
|
if (self.capped) {
|
||||||
opts = {capped: true, size: self.cappedSize};
|
opts = {capped: true, size: self.cappedSize};
|
||||||
}
|
}
|
||||||
self.mainDb.createCollection(self.collection, opts, function() {
|
db.createCollection(self.collection, opts, function() {
|
||||||
cb(null);
|
cb(null, db);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function authorizeDb(cb) {
|
function authorizeDb(db, cb) {
|
||||||
if (self.username && self.password) {
|
if (self.username && self.password) {
|
||||||
self.mainDb.authenticate(self.username, self.password,
|
db.authenticate(self.username, self.password,
|
||||||
function(err, result) {
|
function(err, result) {
|
||||||
if (err) {
|
if (err) {
|
||||||
console.error('winston-mongodb: error initialising logger', err);
|
console.error('winston-mongodb: error initialising logger', err);
|
||||||
self.mainDb.close();
|
db.close();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!result) {
|
if (!result) {
|
||||||
console.error('winston-mongodb: invalid username or password');
|
console.error('winston-mongodb: invalid username or password');
|
||||||
self.mainDb.close();
|
db.close();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
cb(null);
|
cb(null, db);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
cb(null);
|
cb(null, db);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ('string' === typeof this.db) {
|
if ('string' === typeof this.db) {
|
||||||
|
@ -126,16 +134,17 @@ var MongoDB = exports.MongoDB = function(options) {
|
||||||
console.error('winston-mongodb: error initialising logger', err);
|
console.error('winston-mongodb: error initialising logger', err);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
self.mainDb = db;
|
setupDatabaseAndEmptyQueue(db);
|
||||||
authorizeDb(function() {
|
});
|
||||||
createCollection(processOpQuery);
|
} 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 {
|
} else {
|
||||||
this.mainDb = this.db;
|
setupDatabaseAndEmptyQueue(this.db);
|
||||||
authorizeDb(function() {
|
|
||||||
createCollection(processOpQuery);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -161,8 +170,8 @@ winston.transports.MongoDB = MongoDB;
|
||||||
* @param {Function} callback Continuation to respond to when complete.
|
* @param {Function} callback Continuation to respond to when complete.
|
||||||
*/
|
*/
|
||||||
MongoDB.prototype.log = function(level, msg, opt_meta, callback) {
|
MongoDB.prototype.log = function(level, msg, opt_meta, callback) {
|
||||||
if (!this.mainDb) {
|
if (!this.logDb) {
|
||||||
this._opQuery.push({
|
this._opQueue.push({
|
||||||
method: 'log',
|
method: 'log',
|
||||||
args: arguments
|
args: arguments
|
||||||
});
|
});
|
||||||
|
@ -186,7 +195,7 @@ MongoDB.prototype.log = function(level, msg, opt_meta, callback) {
|
||||||
callback(err, null);
|
callback(err, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
self.mainDb.collection(self.collection, function(err, col) {
|
self.logDb.collection(self.collection, function(err, col) {
|
||||||
if (err) {
|
if (err) {
|
||||||
onError(err);
|
onError(err);
|
||||||
return;
|
return;
|
||||||
|
@ -225,8 +234,8 @@ MongoDB.prototype.log = function(level, msg, opt_meta, callback) {
|
||||||
* @return {*}
|
* @return {*}
|
||||||
*/
|
*/
|
||||||
MongoDB.prototype.query = function(opt_options, callback) {
|
MongoDB.prototype.query = function(opt_options, callback) {
|
||||||
if (!this.mainDb) {
|
if (!this.logDb) {
|
||||||
this._opQuery.push({
|
this._opQueue.push({
|
||||||
method: 'query',
|
method: 'query',
|
||||||
args: arguments
|
args: arguments
|
||||||
});
|
});
|
||||||
|
@ -257,7 +266,7 @@ MongoDB.prototype.query = function(opt_options, callback) {
|
||||||
opt.fields = options.fields;
|
opt.fields = options.fields;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.mainDb.collection(this.collection, function(err, col) {
|
this.logDb.collection(this.collection, function(err, col) {
|
||||||
if (err) {
|
if (err) {
|
||||||
callback(err);
|
callback(err);
|
||||||
return;
|
return;
|
||||||
|
@ -293,8 +302,8 @@ MongoDB.prototype.stream = function(options, stream) {
|
||||||
var self = this;
|
var self = this;
|
||||||
var start = options.start;
|
var start = options.start;
|
||||||
|
|
||||||
if (!this.mainDb) {
|
if (!this.logDb) {
|
||||||
this._opQuery.push({
|
this._opQueue.push({
|
||||||
method: 'stream',
|
method: 'stream',
|
||||||
args: [options, stream]
|
args: [options, stream]
|
||||||
});
|
});
|
||||||
|
@ -310,7 +319,7 @@ MongoDB.prototype.stream = function(options, stream) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (start != null) {
|
if (start != null) {
|
||||||
this.mainDb.collection(this.collection, function(err, col) {
|
this.logDb.collection(this.collection, function(err, col) {
|
||||||
if (err) {
|
if (err) {
|
||||||
stream.emit('error', err);
|
stream.emit('error', err);
|
||||||
return;
|
return;
|
||||||
|
@ -334,7 +343,7 @@ MongoDB.prototype.stream = function(options, stream) {
|
||||||
return stream;
|
return stream;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.mainDb.collection(this.collection, function(err, col) {
|
this.logDb.collection(this.collection, function(err, col) {
|
||||||
if (err) {
|
if (err) {
|
||||||
stream.emit('error', err);
|
stream.emit('error', err);
|
||||||
return;
|
return;
|
||||||
|
@ -387,8 +396,8 @@ MongoDB.prototype.streamPoll = function(options, stream) {
|
||||||
var start = options.start;
|
var start = options.start;
|
||||||
var last;
|
var last;
|
||||||
|
|
||||||
if (!this.mainDb) {
|
if (!this.logDb) {
|
||||||
this._opQuery.push({
|
this._opQueue.push({
|
||||||
method: 'streamPoll',
|
method: 'streamPoll',
|
||||||
args: [options, stream]
|
args: [options, stream]
|
||||||
});
|
});
|
||||||
|
@ -408,7 +417,7 @@ MongoDB.prototype.streamPoll = function(options, stream) {
|
||||||
};
|
};
|
||||||
|
|
||||||
(function check() {
|
(function check() {
|
||||||
self.mainDb.collection(self.collection, function(err, col) {
|
self.logDb.collection(self.collection, function(err, col) {
|
||||||
if (err) {
|
if (err) {
|
||||||
stream.emit('error', err);
|
stream.emit('error', err);
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"name": "winston-mongodb",
|
"name": "winston-mongodb",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"version": "1.0.1",
|
"version": "1.1.0",
|
||||||
"description": "A MongoDB transport for winston",
|
"description": "A MongoDB transport for winston",
|
||||||
"author": "Charlie Robbins <charlie.robbins@gmail.com>",
|
"author": "Charlie Robbins <charlie.robbins@gmail.com>",
|
||||||
"contributors": [
|
"contributors": [
|
||||||
|
@ -19,7 +19,8 @@
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"winston": "0.9.x",
|
"winston": "0.9.x",
|
||||||
"vows": "0.8.x"
|
"vows": "0.8.x",
|
||||||
|
"bluebird": "2.9.x"
|
||||||
},
|
},
|
||||||
"main": "./lib/winston-mongodb",
|
"main": "./lib/winston-mongodb",
|
||||||
"scripts": { "test": "vows test/*-test.js --spec" }
|
"scripts": { "test": "vows test/*-test.js --spec" }
|
||||||
|
|
|
@ -7,6 +7,8 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
var vows = require('vows');
|
var vows = require('vows');
|
||||||
|
var mongodb = require('mongodb');
|
||||||
|
var Promise = require('bluebird');
|
||||||
var transport = require('winston/test/transports/transport');
|
var transport = require('winston/test/transports/transport');
|
||||||
var MongoDB = require('../lib/winston-mongodb').MongoDB;
|
var MongoDB = require('../lib/winston-mongodb').MongoDB;
|
||||||
|
|
||||||
|
@ -14,10 +16,24 @@ vows.describe('winston-mongodb').addBatch({
|
||||||
'An instance of the MongoDB Transport': transport(MongoDB, {
|
'An instance of the MongoDB Transport': transport(MongoDB, {
|
||||||
db: 'mongodb://localhost/winston'
|
db: 'mongodb://localhost/winston'
|
||||||
}),
|
}),
|
||||||
'And instance of the MongoDB Transport on capped collection':
|
'An instance of the MongoDB Transport on capped collection':
|
||||||
transport(MongoDB, {
|
transport(MongoDB, {
|
||||||
db: 'mongodb://localhost/winston',
|
db: 'mongodb://localhost/winston',
|
||||||
capped: true,
|
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);
|
}).export(module);
|
||||||
|
|
Загрузка…
Ссылка в новой задаче