ft-metrics
Version:
A node module that includes helper methods/middleware for recording metrics
135 lines (118 loc) • 3.02 kB
JavaScript
'use strict';
var Process = require('./lib/Process.js');
var stats = require('./lib/stats.js');
var _ = require('underscore');
function FtMetrics() {
var defaults = {
movingAveragePeriod: 60,
maxSampleSize: 10000
};
this.reset();
this.configure(defaults);
this.endpoint = this.endpoint.bind(this);
}
FtMetrics.prototype = {
configure: function(options) {
options = options || {};
this.movingAveragePeriod = options.movingAveragePeriod || this.movingAveragePeriod;
this.maxSampleSize = options.maxSampleSize || this.movingAveragePeriod;
if(this.gcInterval) {
clearInterval(this.gcInterval);
}
this.gcInterval = setInterval(this.garbageCollect.bind(this),
this.movingAveragePeriod * 1000);
},
reset: function() {
this.data = {};
this.processes = {};
},
count: function(key, unit, description) {
if(this.data[key] && this.data[key].type === 'counter') {
this.data[key].val += 1;
} else {
this.data[key] = {
type: 'counter',
val: 1,
unit: unit,
description: description,
since: new Date()
};
}
},
setFlag: function(key, value, description) {
value = (typeof value === 'undefined') ? true : value;
if(this.data[key] && this.data[key].type === 'boolean') {
this.data[key].val = value;
} else {
this.data[key] = {
type: 'boolean',
val: value,
description: description,
};
}
},
garbageCollect: function() {
var key;
var now = (new Date()).getTime();
for(key in this.processes) {
if(this.processes.hasOwnProperty(key)) {
this.processes[key] = this.filterOnlyRecentProcesses(key, now);
}
}
},
filterOnlyRecentProcesses: function(key, now) {
var period = this.movingAveragePeriod;
return _.filter(this.processes[key], function(proc) {
if(proc.startTime) {
return (now - proc.startTime.getTime()) < (period * 1000);
} else {
return false;
}
});
},
createProcess: function(key) {
var process = new Process();
if(!this.processes.hasOwnProperty(key)) {
this.processes[key] = [];
}
if(this.processes[key].length >= this.maxSampleSize) {
this.processes[key].shift();
}
this.processes[key].push(process);
return process;
},
movingAverage: function(key) {
if(!this.data.hasOwnProperty(key)) {
this.data[key] = {};
}
var times = _.map(this.processes[key], function(proc) {
return proc.duration / 1000;
});
var data = stats.getStats(times);
data.period = this.movingAveragePeriod;
this.data[key] = data;
},
getJSON: function() {
var self = this;
_.each(this.processes, function(process, key) {
self.movingAverage(key);
});
return { data: this.data};
},
endpoint: function(req, res) {
res.send(this.getJSON());
},
monitor: function(key) {
var self = this;
return function(req, res, next) {
key = key || req.route.path;
var thisProcess = self.createProcess(key);
req.on('end', function() {
thisProcess.end();
});
thisProcess.start();
next();
};
}
};
module.exports = new FtMetrics();