Permalink
Browse files

Added connect middleware

  • Loading branch information...
1 parent 56ddd7d commit 49592e2bbda7b641d4df293709ca2cdb6488315d @DamonOehlman committed Aug 31, 2011
Showing with 181 additions and 27 deletions.
  1. +31 −1 README.md
  2. +24 −3 lib/collector.js
  3. +39 −0 lib/middleware.js
  4. +24 −14 lib/sampledb.js
  5. +63 −9 test/db.js
View
@@ -1,3 +1,33 @@
# Voyeur.io Collector
-The collector is the engine room of Voyeur.
+The collector is the engine room of Voyeur. A number of different collection agents are implemented, and more are on their way.
+
+## Usage
+
+Using the voyeur.io collector in a project is very simple. First install the npm package:
+
+`npm install voyeur`
+
+Then, in your application code doing something similar to the following:
+
+```js
+var voyeur = require('voyeur'),
+ collector = voyeur.collectToDB();
+
+// other stuff goes here
+
+// on exit, stop collecting (this closes the db nicely)
+process.on('exit', function() {
+ collector.stop();
+});
+```
+
+No in the above configuration, the collector will happily run up the default agents and save the data to a [leveldb](http://leveldb.googlecode.com/) database in the `samples` directory. Presumably, however, you also want to get the data out and report on it somehow.
+
+The simplest way to do this is through using the [Connect](http://senchalabs.github.com/connect) middleware that is included in the voyeur package:
+
+To be completed
+
+## Advanced Usage
+
+To be completed
View
@@ -3,6 +3,7 @@ var fs = require('fs'),
events = require('events'),
util = require('util'),
path = require('path'),
+ middleware = require('./middleware'),
SampleDB = require('./sampledb').SampleDB,
agents = [];
@@ -89,7 +90,7 @@ Collector.prototype.scheduleAgents = function() {
});
}
else {
- setInterval(function() {
+ agent.intervalId = setInterval(function() {
collector.runAgent(agent);
}, agent.frequency);
} // if..else
@@ -104,6 +105,18 @@ Collector.prototype.runAgent = function(agent) {
});
}; // runAgent
+Collector.prototype.stop = function() {
+ // reset the agents
+ this.agents.forEach(function(agent) {
+ if (agent.intervalId) {
+ clearInterval(agent.intervalId);
+ } // if
+ else if (agent.cron && agent.cron.timer) {
+ clearInterval(agent.cron.timer);
+ } // if
+ });
+}; // stop
+
exports.collectToDB = function(path, opts) {
var db, collector;
@@ -123,9 +136,17 @@ exports.collectToDB = function(path, opts) {
collector: collector,
db: db,
+ json: middleware.json,
+
stop: function() {
+ // stop the collector
+ collector.stop();
+
+ // close the db
db.close();
- process.exit();
}
};
-};
+};
+
+// expose the middleware
+exports.middleware = middleware;
View
@@ -0,0 +1,39 @@
+exports.json = function(db, opts) {
+ // initialise opts
+ opts = opts || {};
+ opts.path = '/samples';
+ opts.defaultAge = opts.defaultAge || 30000;
+ opts.authKey = undefined;
+
+ // initialise variables
+ var rePath = new RegExp('^' + opts.path + '/?(\\d*)');
+
+ return function(req, res, next) {
+ if (req && req.url) {
+ var match = rePath.exec(req.url);
+
+ // if we have a match, then respond to the request, otherwise pass to the next handler
+ if (match) {
+ // initialise the start tick
+ var startTick = parseInt(match[1], 10) || (new Date().getTime() - opts.defaultAge);
+
+ // get the requested samples
+ db.getSince(startTick, function(err, details) {
+ res.setHeader('Content-Type', 'application/json');
+
+ if (! err) {
+ res.statusCode = 200;
+ res.end(JSON.stringify(details));
+ }
+ else {
+ res.statusCode = 500;
+ res.end(err);
+ } // if..else
+ });
+ }
+ else {
+ next();
+ } // if..else
+ } // if
+ };
+};
View
@@ -7,9 +7,16 @@ var SampleDB = exports.SampleDB = function(path) {
SampleDB.prototype.close = function() {
this.storage.close();
+ this.storage = null;
}; // close
SampleDB.prototype.getSince = function(time, callback, opts) {
+ // if the storage has been closed, then exit
+ if (! this.storage) {
+ callback('storage closed', null);
+ return;
+ } // if
+
// initialise options
opts = opts || {};
opts.maxItems = opts.maxItems || 1000;
@@ -86,22 +93,25 @@ SampleDB.prototype.getSince = function(time, callback, opts) {
}; // getSince
SampleDB.prototype.save = function(type, data, details) {
- var tick = new Date().getTime(),
- entryKey = tick + '_' + type;
+ // if the storage has been closed, then exit
+ if (this.storage) {
+ var tick = new Date().getTime(),
+ entryKey = tick + '_' + type;
- // first save the base data
- this.storage.put(
- {},
- new Buffer(entryKey),
- new Buffer(JSON.stringify(data))
- );
-
- // next add the details
- if (details) {
+ // first save the base data
this.storage.put(
{},
- new Buffer(entryKey + '_' + details),
- new Buffer(JSON.stringify(details))
- );
+ new Buffer(entryKey),
+ new Buffer(JSON.stringify(data))
+ );
+
+ // next add the details
+ if (details) {
+ this.storage.put(
+ {},
+ new Buffer(entryKey + '_' + details),
+ new Buffer(JSON.stringify(details))
+ );
+ } // if
} // if
};
View
@@ -1,20 +1,21 @@
var vows = require('vows'),
assert = require('assert'),
- collector = require('../lib/collector'),
- startTick = new Date().getTime();
+ voyeur = require('../lib/collector'),
+ startTick = new Date().getTime(),
+ collector = voyeur.collectToDB();
-vows.describe('Collection to DB').addBatch({
+var suite = vows.describe('Collector to DB');
+
+suite.addBatch({
'When collecting samples': {
topic: function() {
- var collectionProcess = collector.collectToDB(),
- callback = this.callback;
-
+ var callback = this.callback;
+
setTimeout(function() {
- collectionProcess.db.getSince(startTick, callback, {
+ collector.db.getSince(startTick, callback, {
maxItems: 1000,
includeDetail: false
});
- collectionProcess.stop();
}, 2000);
},
@@ -34,4 +35,57 @@ vows.describe('Collection to DB').addBatch({
assert.ok(Math.abs(results.end - (startTick + 2000)) < 500);
}
}
-}).run();
+});
+
+suite.addBatch({
+ 'Middleware tests': {
+ topic: function() {
+ // create a mock response
+ var res = (function() {
+ var _this = {
+ out: '',
+ headers: {},
+
+ setHeader: function(name, val) { _this.headers[name] = val; },
+ end: function(value) { _this.out = value; }
+ };
+
+ return _this;
+ })();
+
+ this.callback(null, collector.json(collector.db), res);
+ },
+
+ 'middleware is created': function(err, handler) {
+ assert.ok(handler);
+ },
+
+ 'middleware copes with empty requests': function(err, handler) {
+ assert.doesNotThrow(function() {
+ handler(null);
+ });
+ },
+
+ 'responds to general request': function(err, handler, res) {
+ handler({ url: '/samples' }, res);
+ assert.ok(res.out);
+ },
+
+ 'responds to specific request': function(err, handler, res) {
+ handler({ url: '/samples/' + startTick }, res);
+ assert.ok(res.out);
+ }
+ }
+});
+
+suite.addBatch({
+ 'Shutdown collection process': {
+ 'shutdown': function(c) {
+ assert.doesNotThrow(function() {
+ collector.stop();
+ });
+ }
+ }
+});
+
+suite.run();

0 comments on commit 49592e2

Please sign in to comment.