metrics-server
Version:
Basic metrics server and client.
331 lines (267 loc) • 6.47 kB
JavaScript
var fs = require('fs');
var express = require('express');
var compression = require('compression');
var responseTime = require('response-time');
var uuid = require('node-uuid');
var WebSocketServer = require('ws').Server;
var async = require('async');
var mongoose = require('../mongoose');
module.exports.createServer = function(options) {
return new Server(options);
};
function Watcher(ws) {
this.ws = ws;
this.id = uuid.v4();
this.groups = {};
this.timmer = false;
this.stopped = false;
}
Watcher.prototype.add = function(group, schema) {
if (!this.groups[group]) {
this.groups[group] = [];
}
this.groups[group].push(schema);
if(!this.timmer){
this.timmer=true;
this.startTimmer();
}
};
Watcher.prototype.setToHappen = function(fn, d) {
var t = d.getTime() - Date.now();
return setTimeout(fn, t);
};
Watcher.prototype.startTimmer = function() {
var self = this;
if (this.stopped) {
return;
}
var now = new Date();
var timestamp = new Date(now.getFullYear(), now.getMonth(), now.getDate(), now.getHours(), now.getMinutes(), now.getSeconds() + 1);
this.setToHappen(function() {
self.poller(self.startTimmer.bind(self));
}, timestamp);
};
Watcher.prototype.remove = function(group, schema) {
if (this.groups[group]) {
this.groups[group].splice(this.groups[group].indexOf(schema), 1);
if (this.groups[group].length == 0) {
delete this.groups[group];
}
}
};
Watcher.prototype.poller = function(cb) {
console.log('poller')
var self = this;
var i = 0;
var l = Object.keys(this.groups).length - 1;
Object.keys(this.groups).forEach(function(group) {
var tasks = [];
self.groups[group].forEach(function(schema) {
tasks.push(function(next) {
mongoose.TimeSeries(schema).latest({}, next);
});
});
async.parallel(tasks, function(err, results) {
if (err)
return;
self.ws.send(JSON.stringify({
group : group,
results : results
}), function() {
console.log('poller', i, l)
if (i++ == l) {
cb()
}
});
});
});
};
Watcher.prototype.close = function() {
this.groups = {};
this.stopped = true;
};
function Server(options) {
this.options = options;
this.watch = {};
};
Server.prototype.ws = function() {
var watch = this.watch;
this.wss = new WebSocketServer({
server : this.server
});
this.wss.on('connection', function(ws) {
console.log('connection')
var watcher = new Watcher(ws);
watch[watcher.id] = watcher;
ws.on('message', function(data, flags) {
console.log(data)
try {
var json = JSON.parse(data);
} catch(e) {
return console.log(e);
}
if (!json.event || !json.group || !json.schema) {
return console.log('need json.event || json.group || json.schema');
}
switch (json.event) {
case 'start':
watcher.add(json.group, json.schema);
break;
case 'stop':
watcher.remove(json.group, json.schema);
break;
default:
}
});
ws.on('close', function(code, message) {
watcher.close();
delete watch[watcher.id];
});
});
};
Server.prototype.registerServer = function() {
var self = this;
var app = this.app = express();
app.use(compression());
app.use(responseTime({
digits : 5
}));
// respond
var server = this.server = require('http').createServer(app);
app.all('*', function(req, res, next) {
res.header("Access-Control-Allow-Origin", "*");
res.header('Access-Control-Allow-Methods', 'GET');
res.header("Access-Control-Allow-Headers", "X-Requested-With");
next();
});
app.get("/metric/:token", this.getMetric.bind(this));
app.get("/min/:token", this.min.bind(this));
app.get("/max/:token", this.max.bind(this));
app.get("/latest/:token", this.latest.bind(this));
app.get("/find/:token", this.find.bind(this));
this.ws();
server.listen(this.options.port, this.options.host);
};
Server.prototype.latest = function(req, res) {
var token = req.params.token;
mongoose.TimeSeries(token).latest({}, function(error, data) {
res.send(data);
});
};
Server.prototype.find = function(req, res) {
var token = req.params.token;
mongoose.TimeSeries(token).model.find(req.query || {}, function(error, data) {
res.setHeader('x-count', data.length);
res.send(data);
});
};
Server.prototype.getMetric = function(req, res) {
var token = req.params.token;
var from = req.query.from;
var to = req.query.to;
var interval = req.query.interval || 'seconds';
var type = req.query.type || 'sum';
if (!from) {
from = new Date(new Date() - 1000 * 60 * 60 * 24);
} else {
if (!isNaN(from)) {
from = Number(from);
}
from = Date.past(from);
}
if (to) {
if (!isNaN(to)) {
to = Number(to);
}
to = new Date(to);
}
var model = mongoose.TimeSeries(token);
if (model[interval]) {
mongoose.TimeSeries(token)[interval]({
from : from,
to : to,
type : type
}, function(error, data) {
res.setHeader('x-count', data.length);
res.send(data);
});
} else {
res.send(new Error('bad interval: days,hours,minutes,seconds'));
}
};
Server.prototype.min = function(req, res) {
var token = req.params.token;
var from = req.query.from;
var to = req.query.to;
if (!from) {
from = new Date(new Date() - 1000 * 60 * 60 * 24);
} else {
if (!isNaN(from)) {
from = Number(from);
}
from = Date.past(from);
}
if (to) {
if (!isNaN(to)) {
to = Number(to);
}
to = new Date(to);
} else {
to = new Date();
}
var model = mongoose.TimeSeries(token);
mongoose.TimeSeries(token).min({
from : from,
to : to
}, function(error, min) {
if (error)
throw error;
res.send({
min : min
});
});
};
Server.prototype.max = function(req, res) {
var token = req.params.token;
var from = req.query.from;
var to = req.query.to;
if (!from) {
from = new Date(new Date() - 1000 * 60 * 60 * 24);
} else {
if (!isNaN(from)) {
from = Number(from);
}
from = Date.past(from);
}
if (to) {
if (!isNaN(to)) {
to = Number(to);
}
to = new Date(to);
} else {
to = new Date();
}
var model = mongoose.TimeSeries(token);
mongoose.TimeSeries(token).max({
from : from,
to : to
}, function(error, max) {
if (error)
throw error;
res.send({
max : max
});
});
};
Server.prototype.start = function() {
mongoose.start(this.options.mongodb || {});
this.registerServer();
};
Server.prototype.stop = function() {
var watch = this.watch;
Object.keys(watch).forEach(function(id) {
watch[id].close();
delete watch[id];
});
this.server.close();
};