Skip to content

Commit 9eb3beb

Browse files
committed
Add new uptime claculator
1 parent 0a397ad commit 9eb3beb

File tree

5 files changed

+191
-0
lines changed

5 files changed

+191
-0
lines changed

lib/uptimeCalculator.js

+65
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
var Ping = require('../models/ping');
2+
var CheckEvent = require('../models/checkEvent');
3+
4+
var UptimeCalculator = function(check) {
5+
this.check = check;
6+
}
7+
8+
UptimeCalculator.prototype.getUptimePeriods = function(begin, end, callback) {
9+
var self = this;
10+
this.getPingBeforeTime(begin, function(err1, ping) {
11+
if (err1) return callback(err1);
12+
if (!ping) return callback(null, []);
13+
CheckEvent.find()
14+
.where('check').equals(self.check)
15+
.where('timestamp').gte(begin).lte(end)
16+
.sort({ timestamp: 1 })
17+
.find(function(err2, checkEvents) {
18+
if (err2) return callback(err2);
19+
var periods = [];
20+
var isUp = ping.isUp; // initial state
21+
var currentPeriod = isUp ? [begin] : [];
22+
checkEvents.forEach(function(checkEvent) {
23+
switch (checkEvent.message) {
24+
case 'up':
25+
if (isUp) break; // check passes up while it was already up: ignore
26+
// beginning of an uptime period
27+
currentPeriod.push(checkEvent.timestamp.getTime());
28+
isUp = true;
29+
break;
30+
case 'down':
31+
if (!isUp) break; // check passes down while it was already down: ignore
32+
// end of an uptime period
33+
currentPeriod.push(checkEvent.timestamp.getTime());
34+
periods.push(currentPeriod);
35+
currentPeriod = [];
36+
isUp = false;
37+
break;
38+
}
39+
})
40+
if (isUp) {
41+
// check was up until the end
42+
currentPeriod.push(end);
43+
periods.push(currentPeriod);
44+
};
45+
callback(null, periods);
46+
});
47+
});
48+
}
49+
50+
/**
51+
* Get the last ping preceding a given timestamp
52+
*
53+
* This determines the state of a check at a given time.
54+
*
55+
* @api public
56+
*/
57+
UptimeCalculator.prototype.getPingBeforeTime = function(timestamp, callback) {
58+
Ping.find()
59+
.where('check').equals(this.check)
60+
.where('timestamp').lte(timestamp)
61+
.sort({ timestamp: -1 })
62+
.findOne(callback);
63+
}
64+
65+
module.exports = UptimeCalculator;

makefile

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
test:
2+
NODE_ENV=test mocha test/*/*.js
3+
4+
.PHONY: test

package.json

+3
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,9 @@
1414
"async": "0.1.22",
1515
"socket.io": "0.9.10"
1616
},
17+
"devDependencies": {
18+
"should": "1.1.0"
19+
},
1720
"keywords": ["uptime", "monitoring", "api", "check"],
1821
"repository": "https://github.com/fzaninotto/uptime",
1922
"license": "MIT",

test/lib/test_uptimeCalculator.js

+117
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
var should = require('should');
2+
var async = require('async');
3+
var mongoose = require('../../bootstrap');
4+
var UptimeCalculator = require('../../lib/uptimeCalculator');
5+
var Check = require('../../models/check');
6+
var CheckEvent = require('../../models/checkEvent');
7+
var Ping = require('../../models/ping');
8+
9+
var check1, check2, now; // fixtures
10+
11+
describe('uptimeCalculator', function() {
12+
13+
before(function(done) {
14+
async.parallel([
15+
function(cb) { Ping.collection.drop(cb) },
16+
function(cb) { Check.collection.drop(cb) },
17+
function(cb) { CheckEvent.collection.drop(cb) },
18+
], done);
19+
});
20+
21+
before(function() {
22+
now = Date.now();
23+
});
24+
25+
before(function(done) {
26+
check1 = new Check();
27+
check1.save(function(err) {
28+
if (err) throw (err);
29+
async.series([
30+
function(cb) { Ping.createForCheck(false, now - 3000, 100, check1, 'dummy1', '', cb); },
31+
function(cb) { Ping.createForCheck(false, now - 2000, 100, check1, 'dummy2', '', cb); },
32+
function(cb) { Ping.createForCheck(true, now - 1000, 100, check1, 'dummy3', '', cb); },
33+
function(cb) { Ping.createForCheck(true, now, 100, check1, 'dummy4', '', cb); },
34+
function(cb) { Ping.createForCheck(true, now + 1000, 100, check1, 'dummy5', '', cb); },
35+
function(cb) { Ping.createForCheck(false, now + 2000, 100, check1, 'dummy6', '', cb); },
36+
function(cb) { Ping.createForCheck(true, now + 3000, 100, check1, 'dummy7', '', cb); },
37+
], done);
38+
});
39+
});
40+
41+
before(function(done) {
42+
check2 = new Check();
43+
check2.save(done);
44+
});
45+
46+
describe('#getPingBeforeTime', function() {
47+
48+
it('should return nothing for new Checks', function(done) {
49+
var calculator = new UptimeCalculator(check2);
50+
calculator.getPingBeforeTime(now, function(err, ping) {
51+
if (err) throw (err);
52+
should.not.exist(ping);
53+
done();
54+
});
55+
});
56+
57+
it('should return the latest ping', function(done) {
58+
var calculator = new UptimeCalculator(check1);
59+
calculator.getPingBeforeTime(now, function(err, ping) {
60+
if (err) throw (err);
61+
ping.monitorName.should.eql('dummy4');
62+
done();
63+
});
64+
});
65+
66+
});
67+
68+
describe('#getUptimePeriods', function() {
69+
70+
it('should return empty array when there is no ping', function(done) {
71+
var calculator = new UptimeCalculator(check2);
72+
calculator.getUptimePeriods(Date.now(), Date.now() + 1000, function(err, periods) {
73+
if (err) throw (err);
74+
periods.should.eql([]);
75+
done();
76+
});
77+
});
78+
79+
it('should return the correct period for not finished check', function(done) {
80+
var calculator = new UptimeCalculator(check1);
81+
calculator.getUptimePeriods(now + 3000, now + 6000, function(err, periods) {
82+
if (err) throw (err);
83+
periods.should.eql([ [now + 3000, now + 6000] ]);
84+
done();
85+
});
86+
});
87+
88+
it('should return the correct period for not started check', function(done) {
89+
var calculator = new UptimeCalculator(check1);
90+
calculator.getUptimePeriods(now - 6000, now - 3000, function(err, periods) {
91+
if (err) throw (err);
92+
periods.should.eql([ ]);
93+
done();
94+
});
95+
});
96+
97+
it('should return the correct period for crossing checks', function(done) {
98+
var calculator = new UptimeCalculator(check1);
99+
calculator.getUptimePeriods(now - 6000, now, function(err, periods) {
100+
if (err) throw (err);
101+
periods.should.eql([ [ now - 1000, now ]]);
102+
done();
103+
});
104+
});
105+
106+
it('should return the correct periods', function(done) {
107+
var calculator = new UptimeCalculator(check1);
108+
calculator.getUptimePeriods(now - 3000, now + 3000, function(err, periods) {
109+
if (err) throw (err);
110+
periods.should.eql([ [now - 1000, now + 2000], [now + 3000, now + 3000] ]);
111+
done();
112+
});
113+
});
114+
115+
});
116+
117+
});

test/mocha.opts

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
--reporter spec
2+
--slow 20ms

0 commit comments

Comments
 (0)