Permalink
Browse files

[refactor] Initial commit of refactor from winston core

  • Loading branch information...
1 parent fc405c6 commit e6111b4094d417782ee92d5bde11daca7091e25b @indexzero indexzero committed Jun 7, 2011
Showing with 288 additions and 0 deletions.
  1. +2 −0 .gitignore
  2. +42 −0 README.md
  3. +148 −0 lib/winston-mongodb.js
  4. +23 −0 package.json
  5. +8 −0 test/test-config.json
  6. +65 −0 test/winston-mongodb-test.js
View
@@ -0,0 +1,2 @@
+node_modules
+npm-debug.log
View
@@ -0,0 +1,42 @@
+# winston
+
+A MongoDB transport for [winston][0].
+
+## Installation
+
+### Installing npm (node package manager)
+```
+ curl http://npmjs.org/install.sh | sh
+```
+
+### Installing winston
+```
+ [sudo] npm install winston-mongodb
+```
+
+## Motivation
+`tldr;?`: To break the [winston][0] codebase into small modules that work together.
+
+The [winston][0] codebase has been growing significantly with contributions and other logging transports. This is **awesome**. However, taking a ton of additional dependencies just to do something simple like logging to the Console and a File is overkill.
+
+## Usage
+``` js
+ winston.add(winston.transports.MongoDB, options);
+```
+
+The MongoDB transport takes the following options. 'db' is required:
+
+* __level:__ Level of messages that this transport should log.
+* __silent:__ Boolean flag indicating whether to suppress output.
+* __db:__ The name of the database you want to log to. *[required]*
+* __collection__: The name of the collection you want to store log messages in, defaults to 'log'.
+* __safe:__ Boolean indicating if you want eventual consistency on your log messages, if set to true it requires an extra round trip to the server to ensure the write was committed, defaults to true.
+* __host:__ The host running MongoDB, defaults to localhost.
+* __port:__ The port on the host that MongoDB is running on, defaults to MongoDB's default port.
+
+*Metadata:* Logged as a native JSON object.
+
+#### Author: [Charlie Robbins](http://blog.nodejitsu.com)
+#### Contributors: [Kendrick Taylor](https://github.com/sktaylor)
+
+[0]: https://github.com/indexzero/winston
View
@@ -0,0 +1,148 @@
+/*
+ * mongodb.js: Transport for outputting to a MongoDB database
+ *
+ * (C) 2010 Charlie Robbins, Kendrick Taylor
+ * MIT LICENCE
+ *
+ */
+
+var util = require('util'),
+ mongodb = require('mongodb');
+
+//
+// ### function MongoDB (options)
+// Constructor for the MongoDB transport object.
+//
+var MongoDB = exports.MongoDB = function (options) {
+ options = options || {};
+
+ if (!options.db) {
+ throw new Error("Cannot log to MongoDB without database name.");
+ }
+
+ this.name = 'mongodb';
+ this.db = options.db;
+ this.host = options.host || 'localhost';
+ this.port = options.port || mongodb.Connection.DEFAULT_PORT;
+ this.collection = options.collection || "log";
+ this.safe = options.safe || true;
+ this.level = options.level || 'info';
+ this.silent = options.silent || false;
+ this.username = options.username || null;
+ this.password = options.password || null;
+ this.keepAlive = options.keepAlive || 10000;
+ this.state = 'unopened';
+ this.pending = [];
+
+ this.client = new mongodb.Db(this.db, new mongodb.Server(this.host, this.port, {}), {
+ native_parser : false
+ });
+};
+
+//
+// ### function log (level, msg, [meta], callback)
+// Core logging method exposed to Winston. Metadata is optional.
+//
+MongoDB.prototype.log = function (level, msg, meta, callback) {
+ var self = this;
+
+ if (this.silent) {
+ return callback(null, true);
+ }
+
+ this.open(function (err) {
+ if (err) {
+ return callback(err, false);
+ }
+
+ self._db.collection(self.collection, function (err, col) {
+ if (err) {
+ return callback(err, false);
+ }
+
+ var entry = {
+ level: level,
+ message: msg,
+ meta: meta
+ };
+
+ col.save(entry, { safe: self.safe }, function (err, doc) {
+ if (err) {
+ return callback(err, false);
+ }
+
+ callback(null, true);
+ });
+ });
+ });
+};
+
+MongoDB.prototype.open = function (callback) {
+ var self = this;
+
+ if (this.state === 'opening' || this.state === 'unopened') {
+ //
+ // While opening our MongoDB connection, append any callback
+ // to a list that is managed by this instance.
+ //
+ this.pending.push(callback);
+
+ if (this.state === 'opening') {
+ return;
+ }
+ }
+ else if (this.state === 'opened') {
+ return callback();
+ }
+ else if (this.state === 'error') {
+ return callback(err);
+ }
+
+ function flushPending (err, db) {
+ self._db = db;
+ self.state = 'opened';
+
+ //
+ // Iterate over all callbacks that have accumulated during
+ // the creation of the TCP socket.
+ //
+ for (var i = 0; i < self.pending.length; i++) {
+ self.pending[i]();
+ }
+
+ // Quickly truncate the Array (this is more performant).
+ self.pending.length = 0;
+ }
+
+ function onError (err) {
+ self.state = 'error';
+ self.error = err;
+ flushPending(err, false);
+ }
+
+ this.state = 'opening';
+ this.client.open(function (err, db) {
+ if (err) {
+ return onError(err);
+ }
+ else if (self.username && self.password) {
+ return self.client.authenticate(self.username, self.password, function (err) {
+ return err ? onError(err) : flushPending(null, db);
+ });
+ }
+
+ flushPending(null, db)
+ });
+
+ //
+ // Set a timeout to close the client connection unless `this.keepAlive`
+ // has been set to true in which case it is the responsibility of the
+ // programmer to close the underlying connection.
+ //
+ if (!(this.keepAlive === true)) {
+ setTimeout(function () {
+ self.state = 'unopened';
+ return self._db ? self._db.close() : null
+ }, this.keepAlive);
+ }
+};
View
@@ -0,0 +1,23 @@
+{
+ "name": "winston-mongodb",
+ "description": "A MongoDB transport for winston",
+ "version": "0.2.0",
+ "author": "Charlie Robbins <charlie.robbins@gmail.com>",
+ "contributors": [
+ { "name": "Kendrick Taylor", "email": "sktayloriii@gmail.com" }
+ ],
+ "repository": {
+ "type": "git",
+ "url": "http://github.com/indexzero/winston-mongodb.git"
+ },
+ "keywords": ["logging", "sysadmin", "tools", "winston", "mongodb"],
+ "dependencies": {
+ "mongodb": "0.9.x"
+ },
+ "devDependencies": {
+ "vows": "0.5.x"
+ },
+ "main": "./lib/winston-mongodb",
+ "scripts": { "test": "npm install winston && vows test/*-test.js --spec" },
+ "engines": { "node": ">= 0.4.0" }
+}
View
@@ -0,0 +1,8 @@
+{
+ "transports": {
+ "mongodb": {
+ "db": "winston",
+ "keepAlive": 1000
+ }
+ }
+}
@@ -0,0 +1,65 @@
+/*
+ * mongodb-test.js: Tests for instances of the MongoDB transport
+ *
+ * (C) 2011 Charlie Robbins, Kendrick Taylor
+ * MIT LICENSE
+ *
+ */
+
+var path = require('path'),
+ vows = require('vows'),
+ assert = require('assert'),
+ MongoDB = require('../lib/winston-mongodb').MongoDB;
+
+try {
+ var winston = require('winston'),
+ utils = require('winston/lib/winston/utils'),
+ helpers = require('winston/test/helpers');
+}
+catch (ex) {
+ var error = [
+ 'Error running tests: ' + ex.message,
+ '',
+ 'To run `winston-mongodb tests you need to`',
+ 'install winston locally in this project',
+ '',
+ ' cd ' + path.join(__dirname, '..'),
+ ' npm install winston',
+ ' vows --spec'
+ ].join('\n');
+
+ console.log(error);
+ process.exit(1);
+}
+
+function assertMongoDB (transport) {
+ assert.instanceOf(transport, MongoDB);
+ assert.isFunction(transport.log);
+};
+
+var config = helpers.loadConfig(__dirname),
+ transport = new (MongoDB)(config.transports.mongodb);
+
+vows.describe('winston-mongodb').addBatch({
+ "An instance of the MongoDB Transport": {
+ "should have the proper methods defined": function () {
+ assertMongoDB(transport);
+ },
+ "the log() method": helpers.testNpmLevels(transport, "should log messages to MongoDB", function (ign, err, logged) {
+ assert.isTrue(!err);
+ assert.isTrue(logged);
+ })
+ }
+}).addBatch({
+ "An instance of the MongoDB Transport": {
+ "when the timeout has fired": {
+ topic: function () {
+ setTimeout(this.callback, config.transports.mongodb.keepAlive);
+ },
+ "the log() method": helpers.testNpmLevels(transport, "should log messages to MongoDB", function (ign, err, logged) {
+ assert.isTrue(!err);
+ assert.isTrue(logged);
+ })
+ }
+ }
+}).export(module);

0 comments on commit e6111b4

Please sign in to comment.