upbeat
Version:
Fast health and performance monitoring with process handling
157 lines (122 loc) • 3.56 kB
text/troff
var tempos = require('./tempos');
// handles overall uptitude
export class MetaData {
include $m.EventEmitter;
private {
var HISTORICAL_COUNT = 100;
}
function initialize(config, id) {
this.up = false;
this.times = [];
this.start = new Date();
this.firstTime = true;
this.id = id;
this.rise = config.rise || 1;
this.fall = config.fall || 1;
this.downTime = 0;
this.upTime = 0;
this.totalResTime = 0;
this.totalCount = 0;
this.errorHistory = [];
this.lastErrorMessage = null;
this.lastResponseTime = null;
this.passCount = 0;
this.failCount = 0;
this.runningCount = 0;
}
function setStatus(error, resTime) {
var passed = ! error;
// credit uptime
var now = (new Date()).getTime();
if (this.firstTime) {
this.up = passed;
this.firstTime = false;
}
if (this.lastTime) {
var delta = now - this.lastTime;
if (this.up) {
tempos.increment(this.id, 'uptime', delta);
} else {
tempos.increment(this.id, 'downtime', delta);
}
}
this.lastTime = now;
this.totalCount++;
if (passed) {
this.passCount++;
} else {
this.failCount++;
}
this.mark(passed, resTime);
this.emit((passed ? 'pass' : 'fail'), error);
this.lastCheck = passed;
if (this.wasUp == passed) {
this.runningCount++;
} else {
this.runningCount = 1;
}
if (passed && this.runningCount == this.rise) {
this.up = passed;
this.emit('up');
this.emit('change');
} else if (!passed && this.runningCount == this.fall) {
this.up = passed;
this.emit('down', error);
this.emit('change');
this.errorHistory.push({
error: error,
timestamp: now
});
}
this.wasUp = passed;
}
function uptime(period) {
return tempos.get(period).getCount(this.id + ':uptime');
}
function downtime(period) {
return tempos.get(period).getCount(this.id + ':downtime');
}
function getHistory(period) {
var history = [];
var keys = [];
for (var i=1; i<arguments.length; i++) {
keys.push(this.id + ':' + arguments[i]);
}
var tempo = tempos.get(period);
var tempHistory = keys.map(function (key) {
return tempo.getHistory(key)
});
foreach (var row in tempHistory) {
var length = row.length;
foreach (var bucket:j in row) {
history[j] = history[j] || [];
history[j].push(row[length - j - 1]);
}
}
return history;
}
function plotResponseTimes(period) {
return this.getHistory(period, 'passed-count', 'passed-resp').map(#(row) {
return row[0] && row[1] ? Math.round(row[1] / row[0]) : null;
});
}
function averageResponseTime() {
var totalResp = tempos.day.getCount(this.id + ':passed-resp');
var totalCount = tempos.day.getCount(this.id + ':passed-count');
if (this.totalCount == 0) return null;
return Math.round(totalResp / totalCount);
}
function total(attr, period) {
return tempos.get(period).getCount(this.id + ":" + attr);
}
function mark(passed, time) {
var pre = passed ? 'passed' : 'failed';
tempos.increment(this.id, pre + '-resp', time);
tempos.increment(this.id, pre + '-count', 1);
tempos.increment(this.id, pre, 1);
this.totalResTime += time;
this.lastResponseTime = time;
this.times.push([ passed, time ]);
if (this.times.length > HISTORICAL_COUNT) this.times.shift();
}
}