Compare commits
1 Commits
developmen
...
feature/ZE
Author | SHA1 | Date |
---|---|---|
Jonathan Gramain | 00cfbafa55 |
|
@ -1,6 +1,7 @@
|
||||||
const httpServer = require('../http/server');
|
const httpServer = require('../http/server');
|
||||||
const werelogs = require('werelogs');
|
const werelogs = require('werelogs');
|
||||||
const errors = require('../../errors');
|
const errors = require('../../errors');
|
||||||
|
const promClient = require('prom-client');
|
||||||
|
|
||||||
function sendError(res, log, error, optMessage) {
|
function sendError(res, log, error, optMessage) {
|
||||||
res.writeHead(error.code);
|
res.writeHead(error.code);
|
||||||
|
@ -24,10 +25,6 @@ function sendSuccess(res, log, msg) {
|
||||||
res.end(message);
|
res.end(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
function constructEndpoints(ns, path) {
|
|
||||||
return `/${ns}/${path}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
function checkStub(log) { // eslint-disable-line
|
function checkStub(log) { // eslint-disable-line
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -38,19 +35,20 @@ class HealthProbeServer extends httpServer {
|
||||||
super(params.port, logging);
|
super(params.port, logging);
|
||||||
this.logging = logging;
|
this.logging = logging;
|
||||||
this.setBindAddress(params.bindAddress || 'localhost');
|
this.setBindAddress(params.bindAddress || 'localhost');
|
||||||
this._namespace = params.namespace || '_/health';
|
|
||||||
const livenessURI = constructEndpoints(this._namespace,
|
|
||||||
params.livenessURI || 'liveness');
|
|
||||||
const readinessURI = constructEndpoints(this._namespace,
|
|
||||||
params.readinessURI || 'readiness');
|
|
||||||
// hooking our request processing function by calling the
|
// hooking our request processing function by calling the
|
||||||
// parent's method for that
|
// parent's method for that
|
||||||
this.onRequest(this._onRequest);
|
this.onRequest(this._onRequest);
|
||||||
this._reqHandlers = {};
|
this._reqHandlers = {
|
||||||
this._reqHandlers[livenessURI] = this._onLiveness.bind(this);
|
'/_/health/liveness': this._onLiveness.bind(this),
|
||||||
this._reqHandlers[readinessURI] = this._onReadiness.bind(this);
|
'/_/health/readiness': this._onReadiness.bind(this),
|
||||||
|
'/_/monitoring/metrics': this._onMetrics.bind(this),
|
||||||
|
};
|
||||||
this._livenessCheck = params.livenessCheck || checkStub;
|
this._livenessCheck = params.livenessCheck || checkStub;
|
||||||
this._readinessCheck = params.readinessCheck || checkStub;
|
this._readinessCheck = params.readinessCheck || checkStub;
|
||||||
|
|
||||||
|
this._metrics = {};
|
||||||
|
|
||||||
|
this._initMetrics();
|
||||||
}
|
}
|
||||||
|
|
||||||
onLiveCheck(f) {
|
onLiveCheck(f) {
|
||||||
|
@ -68,8 +66,7 @@ class HealthProbeServer extends httpServer {
|
||||||
if (req.method !== 'GET') {
|
if (req.method !== 'GET') {
|
||||||
sendError(res, log, errors.MethodNotAllowed);
|
sendError(res, log, errors.MethodNotAllowed);
|
||||||
}
|
}
|
||||||
if (req.url.startsWith(`/${this._namespace}`) &&
|
if (req.url in this._reqHandlers) {
|
||||||
req.url in this._reqHandlers) {
|
|
||||||
this._reqHandlers[req.url](req, res, log);
|
this._reqHandlers[req.url](req, res, log);
|
||||||
} else {
|
} else {
|
||||||
sendError(res, log, errors.InvalidURI);
|
sendError(res, log, errors.InvalidURI);
|
||||||
|
@ -92,6 +89,30 @@ class HealthProbeServer extends httpServer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
createCounter(name, help) {
|
||||||
|
const counter = new promClient.Counter({ name, help });
|
||||||
|
this._metrics[name] = counter;
|
||||||
|
return counter;
|
||||||
|
}
|
||||||
|
|
||||||
|
createGauge(name, help) {
|
||||||
|
const gauge = new promClient.Gauge({ name, help });
|
||||||
|
this._metrics[name] = gauge;
|
||||||
|
return gauge;
|
||||||
|
}
|
||||||
|
|
||||||
|
getMetric(name) {
|
||||||
|
return this._metrics[name];
|
||||||
|
}
|
||||||
|
|
||||||
|
_initMetrics() {
|
||||||
|
promClient.collectDefaultMetrics({ timeout: 5000 });
|
||||||
|
}
|
||||||
|
|
||||||
|
_onMetrics(req, res) {
|
||||||
|
res.writeHead(200);
|
||||||
|
res.end(promClient.register.metrics());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = HealthProbeServer;
|
module.exports = HealthProbeServer;
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -35,6 +35,7 @@
|
||||||
"level-sublevel": "~6.6.1",
|
"level-sublevel": "~6.6.1",
|
||||||
"mongodb": "^3.0.1",
|
"mongodb": "^3.0.1",
|
||||||
"node-forge": "^0.7.1",
|
"node-forge": "^0.7.1",
|
||||||
|
"prom-client": "10.2.3",
|
||||||
"simple-glob": "^0.2.0",
|
"simple-glob": "^0.2.0",
|
||||||
"socket.io": "~2.2.0",
|
"socket.io": "~2.2.0",
|
||||||
"socket.io-client": "~2.2.0",
|
"socket.io-client": "~2.2.0",
|
||||||
|
|
|
@ -15,12 +15,12 @@ function makeRequest(meth, uri) {
|
||||||
return req;
|
return req;
|
||||||
}
|
}
|
||||||
|
|
||||||
const endpoints = [
|
const healthcheckEndpoints = [
|
||||||
'/_/health/liveness',
|
'/_/health/liveness',
|
||||||
'/_/health/readiness',
|
'/_/health/readiness',
|
||||||
];
|
];
|
||||||
|
|
||||||
const badEndpoints = [
|
const badHealthcheckEndpoints = [
|
||||||
'/_/health/liveness_thisiswrong',
|
'/_/health/liveness_thisiswrong',
|
||||||
'/_/health/readiness_thisiswrong',
|
'/_/health/readiness_thisiswrong',
|
||||||
];
|
];
|
||||||
|
@ -42,7 +42,7 @@ describe('network.probe.HealthProbeServer', () => {
|
||||||
server.stop();
|
server.stop();
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
endpoints.forEach(ep => {
|
healthcheckEndpoints.forEach(ep => {
|
||||||
it('should perform a GET and ' +
|
it('should perform a GET and ' +
|
||||||
'return 200 OK', done => {
|
'return 200 OK', done => {
|
||||||
makeRequest('GET', ep)
|
makeRequest('GET', ep)
|
||||||
|
@ -82,7 +82,7 @@ describe('network.probe.HealthProbeServer', () => {
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
|
|
||||||
endpoints.forEach(ep => {
|
healthcheckEndpoints.forEach(ep => {
|
||||||
it('should perform a GET and ' +
|
it('should perform a GET and ' +
|
||||||
'return 503 ServiceUnavailable', done => {
|
'return 503 ServiceUnavailable', done => {
|
||||||
makeRequest('GET', ep)
|
makeRequest('GET', ep)
|
||||||
|
@ -117,7 +117,7 @@ describe('network.probe.HealthProbeServer', () => {
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
|
|
||||||
endpoints.forEach(ep => {
|
healthcheckEndpoints.forEach(ep => {
|
||||||
it('should perform a POST and ' +
|
it('should perform a POST and ' +
|
||||||
'return 405 MethodNotAllowed', done => {
|
'return 405 MethodNotAllowed', done => {
|
||||||
makeRequest('POST', ep)
|
makeRequest('POST', ep)
|
||||||
|
@ -152,7 +152,7 @@ describe('network.probe.HealthProbeServer', () => {
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
|
|
||||||
badEndpoints.forEach(ep => {
|
badHealthcheckEndpoints.forEach(ep => {
|
||||||
it('should perform a GET and ' +
|
it('should perform a GET and ' +
|
||||||
'return 400 InvalidURI', done => {
|
'return 400 InvalidURI', done => {
|
||||||
makeRequest('GET', ep)
|
makeRequest('GET', ep)
|
||||||
|
@ -167,4 +167,85 @@ describe('network.probe.HealthProbeServer', () => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('metrics route', () => {
|
||||||
|
let server;
|
||||||
|
function setup(done) {
|
||||||
|
server = new HealthProbeServer({ port: 4042 });
|
||||||
|
server._cbOnListening = done;
|
||||||
|
server.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
before(done => {
|
||||||
|
setup(done);
|
||||||
|
});
|
||||||
|
|
||||||
|
after(done => {
|
||||||
|
server.stop();
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
it('should expose metrics in prometheus format', done => {
|
||||||
|
const counter = server.createCounter(
|
||||||
|
'gizmo_counter', 'Count gizmos');
|
||||||
|
counter.inc();
|
||||||
|
counter.inc(10);
|
||||||
|
const gauge = server.createGauge(
|
||||||
|
'gizmo_gauge', 'Measure gizmos');
|
||||||
|
gauge.set(42);
|
||||||
|
gauge.inc();
|
||||||
|
gauge.dec(10);
|
||||||
|
|
||||||
|
const savedCounter = server.getMetric('gizmo_counter');
|
||||||
|
// check we get the same original counter object
|
||||||
|
assert.strictEqual(savedCounter, counter);
|
||||||
|
|
||||||
|
const savedGauge = server.getMetric('gizmo_gauge');
|
||||||
|
// check we get the same original gauge object
|
||||||
|
assert.strictEqual(savedGauge, gauge);
|
||||||
|
|
||||||
|
assert.strictEqual(server.getMetric('does_not_exist'), undefined);
|
||||||
|
|
||||||
|
const expectedLines = [
|
||||||
|
'# HELP gizmo_counter Count gizmos',
|
||||||
|
'# TYPE gizmo_counter counter',
|
||||||
|
'gizmo_counter 11',
|
||||||
|
'# HELP gizmo_gauge Measure gizmos',
|
||||||
|
'# TYPE gizmo_gauge gauge',
|
||||||
|
'gizmo_gauge 33',
|
||||||
|
];
|
||||||
|
|
||||||
|
makeRequest('GET', '/_/monitoring/metrics')
|
||||||
|
.on('response', res => {
|
||||||
|
assert(res.statusCode === 200);
|
||||||
|
const respBufs = [];
|
||||||
|
res.on('data', data => {
|
||||||
|
respBufs.push(data);
|
||||||
|
});
|
||||||
|
res.on('end', () => {
|
||||||
|
const respContents = respBufs.join('');
|
||||||
|
// check that each expected line is present in
|
||||||
|
// the response
|
||||||
|
const respLines = {};
|
||||||
|
respContents.split('\n').forEach(line => {
|
||||||
|
respLines[line.trimRight()] = true;
|
||||||
|
});
|
||||||
|
expectedLines.forEach(expectedLine => {
|
||||||
|
assert.notStrictEqual(
|
||||||
|
respLines[expectedLine], undefined,
|
||||||
|
'missing expected line in response ' +
|
||||||
|
`'${expectedLine}'`);
|
||||||
|
});
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
res.on('error', err => {
|
||||||
|
assert.ifError(err);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.on('error', err => {
|
||||||
|
assert.ifError(err);
|
||||||
|
done();
|
||||||
|
}).end();
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in New Issue