From 71e68918ca128fff41142dc4406c39ba8ed32f27 Mon Sep 17 00:00:00 2001 From: Harbhajan Singh Date: Fri, 3 Aug 2018 17:46:59 -0400 Subject: [PATCH 1/3] adding seperate metrics server and use prometheus-gc-stats --- README.md | 1 + lib/express.js | 3 ++- lib/hapi.js | 3 ++- lib/http.js | 3 ++- lib/metrics.js | 4 ++++ lib/restify.js | 3 ++- package.json | 3 ++- 7 files changed, 15 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index fce07d5..85c8b7a 100644 --- a/README.md +++ b/README.md @@ -46,6 +46,7 @@ The first argument represents the server of the middleware. The second argument is optional, and allows some configuration of epimetheus - `url` - the url on which to serve metrics. Defaults to `/metrics`. +- `metricsServer` - which server to attach option.url to. (Can be really useful if you like to run metrics endpoint on seperate port); See the following examples of use with [http](#http), [express](#express), [hapi](#hapi) and [restify](#restify). diff --git a/lib/express.js b/lib/express.js index 921a5cc..98a9483 100644 --- a/lib/express.js +++ b/lib/express.js @@ -12,7 +12,8 @@ function middleware (request, response, done) { function instrument (server, options) { server.use(middleware) - server.get(options.url, (req, res) => { + let mertricsEndpointServer = options.metricsServer || server; + mertricsEndpointServer.get(options.url, (req, res) => { res.header('content-type', 'text/plain; charset=utf-8') return res.send(metrics.summary()) }) diff --git a/lib/hapi.js b/lib/hapi.js index bc3f3e5..3649dd8 100644 --- a/lib/hapi.js +++ b/lib/hapi.js @@ -3,7 +3,8 @@ const metrics = require('./metrics') function plugin (options) { var plugin = { register: (server, o, done) => { - server.route({ + let mertricsEndpointServer = options.metricsServer || server; + mertricsEndpointServer.route({ method: 'GET', path: options.url, handler: (req, reply) => { diff --git a/lib/http.js b/lib/http.js index 6ac53eb..63bce0b 100644 --- a/lib/http.js +++ b/lib/http.js @@ -18,7 +18,8 @@ function observeMetrics (request, response) { } function instrument (server, options) { - server.on('request', (request, response) => { + let mertricsEndpointServer = options.metricsServer || server; + mertricsEndpointServer.on('request', (request, response) => { if (request.url === options.url) { sendMetrics(request, response) } else { diff --git a/lib/metrics.js b/lib/metrics.js index f286d1e..12b98e9 100644 --- a/lib/metrics.js +++ b/lib/metrics.js @@ -11,6 +11,10 @@ const metric = { } } +const gcStats = require('prometheus-gc-stats'); +const startGcStats = gcStats(client.register); +startGcStats(); + function ms (start) { var diff = process.hrtime(start) return Math.round((diff[0] * 1e9 + diff[1]) / 1000000) diff --git a/lib/restify.js b/lib/restify.js index ad76785..9d549fd 100644 --- a/lib/restify.js +++ b/lib/restify.js @@ -14,8 +14,9 @@ function middleware (request, response, done) { }; function instrument (server, options) { + let mertricsEndpointServer = options.metricsServer || server; server.use(middleware) - server.get(options.url, (req, res) => { + mertricsEndpointServer.get(options.url, (req, res) => { res.setHeader('Content-Type', 'text/plain; charset=utf-8') /** * Using send uses the native Node handlers rather than the restify one diff --git a/package.json b/package.json index 71ddc94..a5a8e34 100644 --- a/package.json +++ b/package.json @@ -42,6 +42,7 @@ "sinon": "^2.3.6" }, "dependencies": { - "prom-client": "^10.0.0" + "prom-client": "^11.1.1", + "prometheus-gc-stats": "^0.5.1" } } From 41da5760fbd11c024e9d42ce4c7c120094537770 Mon Sep 17 00:00:00 2001 From: Harbhajan Singh Date: Mon, 6 Aug 2018 10:41:34 -0400 Subject: [PATCH 2/3] update version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index a5a8e34..59b0f93 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "epimetheus", - "version": "0.0.1", + "version": "1.0.56", "description": "node middleware to automatically instrument node applications for consumption by prometheus", "main": "index.js", "scripts": { From b08c313c06d14684f08a95f08038968539e2b8f0 Mon Sep 17 00:00:00 2001 From: Harbhajan Singh Date: Tue, 21 Aug 2018 13:30:02 -0400 Subject: [PATCH 3/3] adding test + fix spelling mistake --- lib/express.js | 12 ++++++------ lib/http.js | 12 ++++++------ package.json | 2 +- test/assert-expectations.js | 14 ++++++++++++-- test/express.js | 25 +++++++++++++++++++++---- 5 files changed, 46 insertions(+), 19 deletions(-) diff --git a/lib/express.js b/lib/express.js index 98a9483..3f76034 100644 --- a/lib/express.js +++ b/lib/express.js @@ -1,25 +1,25 @@ const metrics = require('./metrics') -function middleware (request, response, done) { +function middleware(request, response, done) { var start = process.hrtime() - response.on('finish', function () { + response.on('finish', function() { metrics.observe(request.method, request.path, response.statusCode, start) }) return done() }; -function instrument (server, options) { +function instrument(server, options) { server.use(middleware) - let mertricsEndpointServer = options.metricsServer || server; - mertricsEndpointServer.get(options.url, (req, res) => { + let metricsEndpointServer = options.metricsServer || server; + metricsEndpointServer.get(options.url, (req, res) => { res.header('content-type', 'text/plain; charset=utf-8') return res.send(metrics.summary()) }) } -function instrumentable (server) { +function instrumentable(server) { return server && server.defaultConfiguration && server.use } diff --git a/lib/http.js b/lib/http.js index 63bce0b..a2374fd 100644 --- a/lib/http.js +++ b/lib/http.js @@ -1,7 +1,7 @@ const defaults = require('./defaults') const metrics = require('./metrics') -function sendMetrics (request, response) { +function sendMetrics(request, response) { response.writeHead(200, { 'Content-Type': 'text/plain; charset=utf-8' }) @@ -10,16 +10,16 @@ function sendMetrics (request, response) { response.end() } -function observeMetrics (request, response) { +function observeMetrics(request, response) { var start = process.hrtime() response.on('finish', () => { metrics.observe(request.method, request.url, response.statusCode, start) }) } -function instrument (server, options) { - let mertricsEndpointServer = options.metricsServer || server; - mertricsEndpointServer.on('request', (request, response) => { +function instrument(server, options) { + let metricsEndpointServer = options.metricsServer || server; + metricsEndpointServer.on('request', (request, response) => { if (request.url === options.url) { sendMetrics(request, response) } else { @@ -28,7 +28,7 @@ function instrument (server, options) { }) } -function instrumentable (server) { +function instrumentable(server) { return server } diff --git a/package.json b/package.json index 59b0f93..a5a8e34 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "epimetheus", - "version": "1.0.56", + "version": "0.0.1", "description": "node middleware to automatically instrument node applications for consumption by prometheus", "main": "index.js", "scripts": { diff --git a/test/assert-expectations.js b/test/assert-expectations.js index f7abd01..168add0 100644 --- a/test/assert-expectations.js +++ b/test/assert-expectations.js @@ -1,7 +1,7 @@ const request = require('request') const should = require('chai').should() -module.exports = function (options) { +module.exports = function(options) { it('should return 200 for /', (done) => { request('http://localhost:3000/', (e, r, b) => { r.statusCode.should.equal(200) @@ -17,7 +17,8 @@ module.exports = function (options) { }) it('should return 200 for ' + options.url, (done) => { - request('http://localhost:3000' + options.url, (e, r, b) => { + let metricsPort = options.metricsServer ? 3001 : 3000; + request('http://localhost:' + metricsPort + options.url, (e, r, b) => { r.statusCode.should.equal(200) should.exist(r.headers['content-type']) r.headers['content-type'].should.equal('text/plain; charset=utf-8') @@ -29,4 +30,13 @@ module.exports = function (options) { return done(e) }) }) + + if (options.metricsServer) { + it('should return 404 for /metrics on 3000', (done) => { + request('http://localhost:3000/metrics', (e, r, b) => { + r.statusCode.should.equal(404) + return done(e) + }); + }); + } } diff --git a/test/express.js b/test/express.js index 327d933..2ea0db7 100644 --- a/test/express.js +++ b/test/express.js @@ -4,8 +4,10 @@ const epithemeus = require('../index') const assertExpectations = require('./assert-expectations') const assert = require('chai').assert const libExpress = require('../lib/express') +const request = require('request') +const should = require('chai').should() -function setup (options) { +function setup(options) { return describe('express ' + options.url, () => { before((done) => { const app = express() @@ -16,7 +18,13 @@ function setup (options) { app.get('/resource/:id', (req, res) => { res.send() }) - this.server = app.listen(3000, done) + this.server = app.listen(3000, () => { + if (options.metricsServer) { + options.metricsServer.listen(3001, done); + } else { + done() + } + }); }) after((done) => { @@ -32,11 +40,18 @@ setup({ url: '/xxx' }) +setup({ + url: '/metrics', + metricsServer: express() +}) + describe('express should check "instrumentablity" properly', () => { it('should return true when express conditions are correct', () => { // Arrange const server = () => {} - server.defaultConfiguration = { sample: true } + server.defaultConfiguration = { + sample: true + } server.use = () => {} // Act @@ -69,7 +84,9 @@ describe('express should check "instrumentablity" properly', () => { it('should return false when server does not have a use function', () => { // Arrange const server = () => {} - server.defaultConfiguration = { sample: true } + server.defaultConfiguration = { + sample: true + } // Act const actual = libExpress.instrumentable(server)