From 099b1c2302d6a15d9abd49cc2f11d54444770d95 Mon Sep 17 00:00:00 2001 From: Daisuke Taniwaki Date: Sat, 22 May 2021 19:40:58 +0900 Subject: [PATCH 01/19] Add prom-client package --- package-lock.json | 21 +++++++++++++++++++++ package.json | 1 + 2 files changed, 22 insertions(+) diff --git a/package-lock.json b/package-lock.json index 1f29c082..b79d3305 100644 --- a/package-lock.json +++ b/package-lock.json @@ -392,6 +392,11 @@ "tweetnacl": "^0.14.3" } }, + "bintrees": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/bintrees/-/bintrees-1.0.1.tgz", + "integrity": "sha1-DmVcm5wkNeqraL9AJyJtK1WjRSQ=" + }, "brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -1501,6 +1506,14 @@ "fromentries": "^1.2.0" } }, + "prom-client": { + "version": "13.1.0", + "resolved": "https://registry.npmjs.org/prom-client/-/prom-client-13.1.0.tgz", + "integrity": "sha512-jT9VccZCWrJWXdyEtQddCDszYsiuWj5T0ekrPszi/WEegj3IZy6Mm09iOOVM86A4IKMWq8hZkT2dD9MaSe+sng==", + "requires": { + "tdigest": "^0.1.1" + } + }, "psl": { "version": "1.8.0", "resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz", @@ -1789,6 +1802,14 @@ "has-flag": "^3.0.0" } }, + "tdigest": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/tdigest/-/tdigest-0.1.1.tgz", + "integrity": "sha1-Ljyyw56kSeVdHmzZEReszKRYgCE=", + "requires": { + "bintrees": "1.0.1" + } + }, "test-exclude": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", diff --git a/package.json b/package.json index 36f6d77c..b6b8f244 100644 --- a/package.json +++ b/package.json @@ -12,6 +12,7 @@ "commander": "~7.2.0", "http-proxy": "^1.18.1", "lynx": "^0.2.0", + "prom-client": "13.1.0", "strftime": "~0.10.0", "winston": "~3.3.0" }, From 79ee31946f8770f72761b4d7ec85d37f97293b43 Mon Sep 17 00:00:00 2001 From: Daisuke Taniwaki Date: Sat, 22 May 2021 19:41:13 +0900 Subject: [PATCH 02/19] Serve metrics --- lib/configproxy.js | 31 ++++++++++++++++++++-- lib/metrics.js | 66 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 95 insertions(+), 2 deletions(-) create mode 100644 lib/metrics.js diff --git a/lib/configproxy.js b/lib/configproxy.js index 1e862bcc..4dbb4e89 100644 --- a/lib/configproxy.js +++ b/lib/configproxy.js @@ -18,7 +18,8 @@ var http = require("http"), util = require("util"), URL = require("url"), defaultLogger = require("./log").defaultLogger, - querystring = require("querystring"); + querystring = require("querystring"), + metrics = require("./metrics"); function bound(that, method) { // bind a method, to ensure `this=that` when it is called @@ -236,6 +237,7 @@ class ConfigurableProxy extends EventEmitter { this.proxy.on("proxyRes", function (proxyRes, req, res) { that.statsd.increment("requests." + proxyRes.statusCode, 1); + metrics.requestsCount.labels(proxyRes.statusCode).inc(); }); } @@ -342,6 +344,7 @@ class ConfigurableProxy extends EventEmitter { res.write(JSON.stringify(results)); res.end(); that.statsd.increment("api.route.get", 1); + metrics.apiRouteGetCount.inc(); }); } @@ -360,6 +363,7 @@ class ConfigurableProxy extends EventEmitter { res.writeHead(201); res.end(); that.statsd.increment("api.route.add", 1); + metrics.apiRouteAddCount.inc(); }); } @@ -379,18 +383,21 @@ class ConfigurableProxy extends EventEmitter { res.writeHead(code); res.end(); this.statsd.increment("api.route.delete", 1); + metrics.apiRouteDeleteCount.inc(); }); }); } targetForReq(req) { var timer = this.statsd.createTimer("find_target_for_req"); + var metricsTimerEnd = metrics.findTargetForReqSummary.startTimer(); // return proxy target for a given url path var basePath = this.hostRouting ? "/" + parseHost(req) : ""; var path = basePath + decodeURIComponent(URL.parse(req.url).pathname); return this._routes.getTarget(path).then(function (route) { timer.stop(); + metricsTimerEnd(); if (route) { return { prefix: route.prefix, @@ -402,6 +409,7 @@ class ConfigurableProxy extends EventEmitter { updateLastActivity(prefix) { var timer = this.statsd.createTimer("last_activity_updating"); + var metricsTimerEnd = metrics.lastActivityUpdatingSummary.startTimer(); var routes = this._routes; return routes @@ -411,7 +419,8 @@ class ConfigurableProxy extends EventEmitter { return routes.update(prefix, { last_activity: new Date() }); } }) - .then(timer.stop); + .then(timer.stop) + .then(metricsTimerEnd); } _handleProxyErrorDefault(code, kind, req, res) { @@ -431,6 +440,7 @@ class ConfigurableProxy extends EventEmitter { var errMsg = ""; this.statsd.increment("requests." + code, 1); + metrics.requestsCount.labels(code).inc(); if (e) { // avoid stack traces on known not-our-problem errors: // ECONNREFUSED, EHOSTUNREACH (backend isn't there) @@ -604,14 +614,20 @@ class ConfigurableProxy extends EventEmitter { handleProxyWs(req, socket, head) { // Proxy a websocket request this.statsd.increment("requests.ws", 1); + metrics.requestsWsCount.inc(); return this.handleProxy("ws", req, socket, head); } handleProxyWeb(req, res) { this.handleHealthCheck(req, res); if (res.finished) return; + + if (this.handleMetrics(req, res)) { + return; + } // Proxy a web request this.statsd.increment("requests.web", 1); + metrics.requestsWebCount.inc(); return this.handleProxy("web", req, res); } @@ -623,9 +639,20 @@ class ConfigurableProxy extends EventEmitter { } } + handleMetrics(req, res) { + if (req.url === "/metrics") { + return metrics.render().then((s) => { + res.writeHead(200, { "Content-Type": "text/plain; version=0.0.4" }); + res.write(s); + res.end(); + }); + } + } + handleApiRequest(req, res) { // Handle a request to the REST API this.statsd.increment("requests.api", 1); + metrics.requestsApiCount.inc(); if (res) { res.on("finish", () => { this.logResponse(req, res); diff --git a/lib/metrics.js b/lib/metrics.js new file mode 100644 index 00000000..2d674eeb --- /dev/null +++ b/lib/metrics.js @@ -0,0 +1,66 @@ +"use strict"; + +var client = require('prom-client'); +const collectDefaultMetrics = client.collectDefaultMetrics; +collectDefaultMetrics(); + +const apiRouteGetCount = new client.Counter({ + name: 'api_route_get', + help: 'Count of API route get requests', +}); + +const apiRouteAddCount = new client.Counter({ + name: 'api_route_add', + help: 'Count of API route add requests', +}); + +const apiRouteDeleteCount = new client.Counter({ + name: 'api_route_delete', + help: 'Count of API route delete requests', +}); + +const findTargetForReqSummary = new client.Summary({ + name: 'find_target_for_req', + help: 'Summary of find target requests', +}); + +const lastActivityUpdatingSummary = new client.Summary({ + name: 'last_activity_updating', + help: 'Summary of last activity updating requests', +}); + +const requestsWsCount = new client.Counter({ + name: 'requests_ws', + help: 'Count of websocket requests', +}); + +const requestsWebCount = new client.Counter({ + name: 'requests_web', + help: 'Count of web requests', +}); + +const requestsApiCount = new client.Counter({ + name: 'requests_api', + help: 'Count of API requests', +}); + +const requestsCount = new client.Counter({ + name: 'requests', + help: 'Count of requests', + labelNames: ["status"], +}); + +module.exports = { + apiRouteGetCount, + apiRouteAddCount, + apiRouteDeleteCount, + findTargetForReqSummary, + lastActivityUpdatingSummary, + requestsWsCount, + requestsWebCount, + requestsApiCount, + requestsCount, + render: function() { + return client.register.metrics(); + }, +}; From 501ab6059c3dba5a8683d809adbf5553555fcfa9 Mon Sep 17 00:00:00 2001 From: Daisuke Taniwaki Date: Sat, 22 May 2021 19:49:47 +0900 Subject: [PATCH 03/19] Add metrics test --- test/proxy_spec.js | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/test/proxy_spec.js b/test/proxy_spec.js index 2dfbef66..04ee13aa 100644 --- a/test/proxy_spec.js +++ b/test/proxy_spec.js @@ -431,4 +431,11 @@ describe("Proxy Tests", function () { done(); }); }); + + it("metrics request", function (done) { + r(proxyUrl + "/metrics").then((body) => { + expect(body).toContain("process_cpu_user_seconds_total"); + done(); + }); + }); }); From 46f49f972e170c3076575e161de5dc70bf90c014 Mon Sep 17 00:00:00 2001 From: Daisuke Taniwaki Date: Sat, 22 May 2021 20:16:12 +0900 Subject: [PATCH 04/19] Allow to disable metrics --- bin/configurable-http-proxy | 4 +++ lib/configproxy.js | 29 ++++++++------- lib/metrics.js | 71 ++++++++++++++++++++++++++----------- test/proxy_spec.js | 7 ++++ 4 files changed, 79 insertions(+), 32 deletions(-) diff --git a/bin/configurable-http-proxy b/bin/configurable-http-proxy index e2eb6d2e..e69e4ce5 100755 --- a/bin/configurable-http-proxy +++ b/bin/configurable-http-proxy @@ -90,6 +90,7 @@ cli .option("--statsd-host ", "Host to send statsd statistics to") .option("--statsd-port ", "Port to send statsd statistics to", parseInt) .option("--statsd-prefix ", "Prefix to use for statsd statistics") + .option("--disable-metrics", "Disable metrics endpoint") .option("--log-level ", "Log level (debug, info, warn, error)", "info") .option( "--timeout ", @@ -275,6 +276,9 @@ if (args.statsdHost) { log.info("Sending metrics to statsd at " + args.statsdHost + ":" + args.statsdPort || 8125); } +// prometheus options +options.disableMetrics = args.disableMetrics; + // certs need to be provided for https redirection if (!options.ssl && options.redirectPort) { log.error("HTTPS redirection specified but certificates not provided."); diff --git a/lib/configproxy.js b/lib/configproxy.js index 4dbb4e89..050aec7a 100644 --- a/lib/configproxy.js +++ b/lib/configproxy.js @@ -160,6 +160,11 @@ class ConfigurableProxy extends EventEmitter { this.errorTarget = this.errorTarget + "/"; // ensure trailing / } this.errorPath = options.errorPath || path.join(__dirname, "error"); + if (options.disableMetrics) { + this.metrics = metrics.mock; + } else { + this.metrics = metrics; + } if (options.statsd) { this.statsd = options.statsd; } else { @@ -237,7 +242,7 @@ class ConfigurableProxy extends EventEmitter { this.proxy.on("proxyRes", function (proxyRes, req, res) { that.statsd.increment("requests." + proxyRes.statusCode, 1); - metrics.requestsCount.labels(proxyRes.statusCode).inc(); + this.metrics.requestsCount.labels(proxyRes.statusCode).inc(); }); } @@ -344,7 +349,7 @@ class ConfigurableProxy extends EventEmitter { res.write(JSON.stringify(results)); res.end(); that.statsd.increment("api.route.get", 1); - metrics.apiRouteGetCount.inc(); + this.metrics.apiRouteGetCount.inc(); }); } @@ -363,7 +368,7 @@ class ConfigurableProxy extends EventEmitter { res.writeHead(201); res.end(); that.statsd.increment("api.route.add", 1); - metrics.apiRouteAddCount.inc(); + this.metrics.apiRouteAddCount.inc(); }); } @@ -383,14 +388,14 @@ class ConfigurableProxy extends EventEmitter { res.writeHead(code); res.end(); this.statsd.increment("api.route.delete", 1); - metrics.apiRouteDeleteCount.inc(); + this.metrics.apiRouteDeleteCount.inc(); }); }); } targetForReq(req) { var timer = this.statsd.createTimer("find_target_for_req"); - var metricsTimerEnd = metrics.findTargetForReqSummary.startTimer(); + var metricsTimerEnd = this.metrics.findTargetForReqSummary.startTimer(); // return proxy target for a given url path var basePath = this.hostRouting ? "/" + parseHost(req) : ""; var path = basePath + decodeURIComponent(URL.parse(req.url).pathname); @@ -409,7 +414,7 @@ class ConfigurableProxy extends EventEmitter { updateLastActivity(prefix) { var timer = this.statsd.createTimer("last_activity_updating"); - var metricsTimerEnd = metrics.lastActivityUpdatingSummary.startTimer(); + var metricsTimerEnd = this.metrics.lastActivityUpdatingSummary.startTimer(); var routes = this._routes; return routes @@ -440,7 +445,7 @@ class ConfigurableProxy extends EventEmitter { var errMsg = ""; this.statsd.increment("requests." + code, 1); - metrics.requestsCount.labels(code).inc(); + this.metrics.requestsCount.labels(code).inc(); if (e) { // avoid stack traces on known not-our-problem errors: // ECONNREFUSED, EHOSTUNREACH (backend isn't there) @@ -614,7 +619,7 @@ class ConfigurableProxy extends EventEmitter { handleProxyWs(req, socket, head) { // Proxy a websocket request this.statsd.increment("requests.ws", 1); - metrics.requestsWsCount.inc(); + this.metrics.requestsWsCount.inc(); return this.handleProxy("ws", req, socket, head); } @@ -622,12 +627,12 @@ class ConfigurableProxy extends EventEmitter { this.handleHealthCheck(req, res); if (res.finished) return; - if (this.handleMetrics(req, res)) { + if (!this.options.disableMetrics && this.handleMetrics(req, res)) { return; } // Proxy a web request this.statsd.increment("requests.web", 1); - metrics.requestsWebCount.inc(); + this.metrics.requestsWebCount.inc(); return this.handleProxy("web", req, res); } @@ -641,7 +646,7 @@ class ConfigurableProxy extends EventEmitter { handleMetrics(req, res) { if (req.url === "/metrics") { - return metrics.render().then((s) => { + return this.metrics.render().then((s) => { res.writeHead(200, { "Content-Type": "text/plain; version=0.0.4" }); res.write(s); res.end(); @@ -652,7 +657,7 @@ class ConfigurableProxy extends EventEmitter { handleApiRequest(req, res) { // Handle a request to the REST API this.statsd.increment("requests.api", 1); - metrics.requestsApiCount.inc(); + this.metrics.requestsApiCount.inc(); if (res) { res.on("finish", () => { this.logResponse(req, res); diff --git a/lib/metrics.js b/lib/metrics.js index 2d674eeb..dac3a9c7 100644 --- a/lib/metrics.js +++ b/lib/metrics.js @@ -1,55 +1,85 @@ "use strict"; -var client = require('prom-client'); +var client = require("prom-client"); const collectDefaultMetrics = client.collectDefaultMetrics; collectDefaultMetrics(); const apiRouteGetCount = new client.Counter({ - name: 'api_route_get', - help: 'Count of API route get requests', + name: "api_route_get", + help: "Count of API route get requests", }); const apiRouteAddCount = new client.Counter({ - name: 'api_route_add', - help: 'Count of API route add requests', + name: "api_route_add", + help: "Count of API route add requests", }); const apiRouteDeleteCount = new client.Counter({ - name: 'api_route_delete', - help: 'Count of API route delete requests', + name: "api_route_delete", + help: "Count of API route delete requests", }); const findTargetForReqSummary = new client.Summary({ - name: 'find_target_for_req', - help: 'Summary of find target requests', + name: "find_target_for_req", + help: "Summary of find target requests", }); const lastActivityUpdatingSummary = new client.Summary({ - name: 'last_activity_updating', - help: 'Summary of last activity updating requests', + name: "last_activity_updating", + help: "Summary of last activity updating requests", }); const requestsWsCount = new client.Counter({ - name: 'requests_ws', - help: 'Count of websocket requests', + name: "requests_ws", + help: "Count of websocket requests", }); const requestsWebCount = new client.Counter({ - name: 'requests_web', - help: 'Count of web requests', + name: "requests_web", + help: "Count of web requests", }); const requestsApiCount = new client.Counter({ - name: 'requests_api', - help: 'Count of API requests', + name: "requests_api", + help: "Count of API requests", }); const requestsCount = new client.Counter({ - name: 'requests', - help: 'Count of requests', + name: "requests", + help: "Count of requests", labelNames: ["status"], }); +const mockCounter = new Proxy( + {}, + { + get(target, name) { + if (name == "inc") { + return () => {}; + } + if (name == "startTimer") { + return () => { + return () => {}; + }; + } + if (name == "labels") { + return () => { + return mockCounter; + }; + } + }, + } +); + +const mock = new Proxy( + {}, + { + get(target, name) { + return mockCounter; + }, + } +); + module.exports = { apiRouteGetCount, apiRouteAddCount, @@ -60,7 +90,8 @@ module.exports = { requestsWebCount, requestsApiCount, requestsCount, - render: function() { + render: function () { return client.register.metrics(); }, + mock, }; diff --git a/test/proxy_spec.js b/test/proxy_spec.js index 04ee13aa..dff192b3 100644 --- a/test/proxy_spec.js +++ b/test/proxy_spec.js @@ -438,4 +438,11 @@ describe("Proxy Tests", function () { done(); }); }); + + it("disabled metrics request", function (done) { + proxy.proxy.options.disableMetrics = true; + r(proxyUrl + "/metrics") + .then((body) => done.fail("Expected 404")) + .then(done); + }); }); From d5789d75d88c2a715f1a3bc8ea6e28216fdce0c7 Mon Sep 17 00:00:00 2001 From: Daisuke Taniwaki Date: Sat, 22 May 2021 20:17:05 +0900 Subject: [PATCH 05/19] Remove statsd --- bin/configurable-http-proxy | 12 ------------ lib/configproxy.js | 28 ---------------------------- 2 files changed, 40 deletions(-) diff --git a/bin/configurable-http-proxy b/bin/configurable-http-proxy index e69e4ce5..c804084e 100755 --- a/bin/configurable-http-proxy +++ b/bin/configurable-http-proxy @@ -87,9 +87,6 @@ cli ) .option("--insecure", "Disable SSL cert verification") .option("--host-routing", "Use host routing (host as first level of path)") - .option("--statsd-host ", "Host to send statsd statistics to") - .option("--statsd-port ", "Port to send statsd statistics to", parseInt) - .option("--statsd-prefix ", "Prefix to use for statsd statistics") .option("--disable-metrics", "Disable metrics endpoint") .option("--log-level ", "Log level (debug, info, warn, error)", "info") .option( @@ -267,15 +264,6 @@ options.headers = args.customHeader; options.timeout = args.timeout; options.proxyTimeout = args.proxyTimeout; -// statsd options -if (args.statsdHost) { - var lynx = require("lynx"); - options.statsd = new lynx(args.statsdHost, args.statsdPort || 8125, { - scope: args.statsdPrefix || "chp", - }); - log.info("Sending metrics to statsd at " + args.statsdHost + ":" + args.statsdPort || 8125); -} - // prometheus options options.disableMetrics = args.disableMetrics; diff --git a/lib/configproxy.js b/lib/configproxy.js index 050aec7a..2d5fbcd6 100644 --- a/lib/configproxy.js +++ b/lib/configproxy.js @@ -165,24 +165,6 @@ class ConfigurableProxy extends EventEmitter { } else { this.metrics = metrics; } - if (options.statsd) { - this.statsd = options.statsd; - } else { - // Mock the statsd object, rather than pepper the codebase with - // null checks. FIXME: Maybe use a JS Proxy object (if available?) - this.statsd = { - increment: function () {}, - decrement: function () {}, - timing: function () {}, - gauge: function () {}, - set: function () {}, - createTimer: function () { - return { - stop: function () {}, - }; - }, - }; - } if (this.options.defaultTarget) { this.addRoute("/", { @@ -241,7 +223,6 @@ class ConfigurableProxy extends EventEmitter { this.proxyServer.on("upgrade", bound(this, this.handleProxyWs)); this.proxy.on("proxyRes", function (proxyRes, req, res) { - that.statsd.increment("requests." + proxyRes.statusCode, 1); this.metrics.requestsCount.labels(proxyRes.statusCode).inc(); }); } @@ -348,7 +329,6 @@ class ConfigurableProxy extends EventEmitter { res.write(JSON.stringify(results)); res.end(); - that.statsd.increment("api.route.get", 1); this.metrics.apiRouteGetCount.inc(); }); } @@ -367,7 +347,6 @@ class ConfigurableProxy extends EventEmitter { return this.addRoute(path, data).then(function () { res.writeHead(201); res.end(); - that.statsd.increment("api.route.add", 1); this.metrics.apiRouteAddCount.inc(); }); } @@ -387,14 +366,12 @@ class ConfigurableProxy extends EventEmitter { return p.then(() => { res.writeHead(code); res.end(); - this.statsd.increment("api.route.delete", 1); this.metrics.apiRouteDeleteCount.inc(); }); }); } targetForReq(req) { - var timer = this.statsd.createTimer("find_target_for_req"); var metricsTimerEnd = this.metrics.findTargetForReqSummary.startTimer(); // return proxy target for a given url path var basePath = this.hostRouting ? "/" + parseHost(req) : ""; @@ -413,7 +390,6 @@ class ConfigurableProxy extends EventEmitter { } updateLastActivity(prefix) { - var timer = this.statsd.createTimer("last_activity_updating"); var metricsTimerEnd = this.metrics.lastActivityUpdatingSummary.startTimer(); var routes = this._routes; @@ -444,7 +420,6 @@ class ConfigurableProxy extends EventEmitter { // /404?url=%2Fuser%2Ffoo var errMsg = ""; - this.statsd.increment("requests." + code, 1); this.metrics.requestsCount.labels(code).inc(); if (e) { // avoid stack traces on known not-our-problem errors: @@ -618,7 +593,6 @@ class ConfigurableProxy extends EventEmitter { handleProxyWs(req, socket, head) { // Proxy a websocket request - this.statsd.increment("requests.ws", 1); this.metrics.requestsWsCount.inc(); return this.handleProxy("ws", req, socket, head); } @@ -631,7 +605,6 @@ class ConfigurableProxy extends EventEmitter { return; } // Proxy a web request - this.statsd.increment("requests.web", 1); this.metrics.requestsWebCount.inc(); return this.handleProxy("web", req, res); } @@ -656,7 +629,6 @@ class ConfigurableProxy extends EventEmitter { handleApiRequest(req, res) { // Handle a request to the REST API - this.statsd.increment("requests.api", 1); this.metrics.requestsApiCount.inc(); if (res) { res.on("finish", () => { From d6dbf5a9ccfb002f1ea99d062eb5322ee11bba73 Mon Sep 17 00:00:00 2001 From: Daisuke Taniwaki Date: Sat, 22 May 2021 20:18:24 +0900 Subject: [PATCH 06/19] Remove lynx --- package-lock.json | 19 ------------------- package.json | 1 - 2 files changed, 20 deletions(-) diff --git a/package-lock.json b/package-lock.json index b79d3305..c8afb602 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1289,15 +1289,6 @@ "integrity": "sha1-+wMJF/hqMTTlvJvsDWngAT3f7bI=", "dev": true }, - "lynx": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/lynx/-/lynx-0.2.0.tgz", - "integrity": "sha1-eeZnRTDaQYPoeVO9aGFx4HDaULk=", - "requires": { - "mersenne": "~0.0.3", - "statsd-parser": "~0.0.4" - } - }, "make-dir": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", @@ -1307,11 +1298,6 @@ "semver": "^6.0.0" } }, - "mersenne": { - "version": "0.0.4", - "resolved": "https://registry.npmjs.org/mersenne/-/mersenne-0.0.4.tgz", - "integrity": "sha1-QB/ex+whzbngPNPTAhOY2iGycIU=" - }, "mime-db": { "version": "1.46.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.46.0.tgz", @@ -1737,11 +1723,6 @@ "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", "integrity": "sha1-VHxws0fo0ytOEI6hoqFZ5f3eGcA=" }, - "statsd-parser": { - "version": "0.0.4", - "resolved": "https://registry.npmjs.org/statsd-parser/-/statsd-parser-0.0.4.tgz", - "integrity": "sha1-y9JDlTzELv/VSLXSI4jtaJ7GOb0=" - }, "stealthy-require": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/stealthy-require/-/stealthy-require-1.1.1.tgz", diff --git a/package.json b/package.json index b6b8f244..1d14c089 100644 --- a/package.json +++ b/package.json @@ -11,7 +11,6 @@ "dependencies": { "commander": "~7.2.0", "http-proxy": "^1.18.1", - "lynx": "^0.2.0", "prom-client": "13.1.0", "strftime": "~0.10.0", "winston": "~3.3.0" From c368d4612a31548f5b70d806a0f21a9aa7e9e916 Mon Sep 17 00:00:00 2001 From: Daisuke Taniwaki Date: Sat, 22 May 2021 20:30:36 +0900 Subject: [PATCH 07/19] Remove unnecessary timer code --- lib/configproxy.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/lib/configproxy.js b/lib/configproxy.js index 2d5fbcd6..fa4eea44 100644 --- a/lib/configproxy.js +++ b/lib/configproxy.js @@ -378,7 +378,6 @@ class ConfigurableProxy extends EventEmitter { var path = basePath + decodeURIComponent(URL.parse(req.url).pathname); return this._routes.getTarget(path).then(function (route) { - timer.stop(); metricsTimerEnd(); if (route) { return { @@ -400,7 +399,6 @@ class ConfigurableProxy extends EventEmitter { return routes.update(prefix, { last_activity: new Date() }); } }) - .then(timer.stop) .then(metricsTimerEnd); } From 6700d87168c32bcbcdbf7b54fe6cb5d08d442695 Mon Sep 17 00:00:00 2001 From: Daisuke Taniwaki Date: Sat, 22 May 2021 20:41:35 +0900 Subject: [PATCH 08/19] Count API requests --- lib/configproxy.js | 8 +++++--- lib/metrics.js | 13 +++++++------ 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/lib/configproxy.js b/lib/configproxy.js index fa4eea44..705fb68d 100644 --- a/lib/configproxy.js +++ b/lib/configproxy.js @@ -223,7 +223,7 @@ class ConfigurableProxy extends EventEmitter { this.proxyServer.on("upgrade", bound(this, this.handleProxyWs)); this.proxy.on("proxyRes", function (proxyRes, req, res) { - this.metrics.requestsCount.labels(proxyRes.statusCode).inc(); + this.metrics.requestsProxyCount.labels(proxyRes.statusCode).inc(); }); } @@ -418,7 +418,7 @@ class ConfigurableProxy extends EventEmitter { // /404?url=%2Fuser%2Ffoo var errMsg = ""; - this.metrics.requestsCount.labels(code).inc(); + this.metrics.requestsProxyCount.labels(code).inc(); if (e) { // avoid stack traces on known not-our-problem errors: // ECONNREFUSED, EHOSTUNREACH (backend isn't there) @@ -627,9 +627,11 @@ class ConfigurableProxy extends EventEmitter { handleApiRequest(req, res) { // Handle a request to the REST API - this.metrics.requestsApiCount.inc(); if (res) { res.on("finish", () => { + if (req.url !== "/metrics") { + this.metrics.requestsApiCount.labels(res.statusCode).inc(); + } this.logResponse(req, res); }); } diff --git a/lib/metrics.js b/lib/metrics.js index dac3a9c7..09537662 100644 --- a/lib/metrics.js +++ b/lib/metrics.js @@ -39,14 +39,15 @@ const requestsWebCount = new client.Counter({ help: "Count of web requests", }); +const requestsProxyCount = new client.Counter({ + name: "requests_proxy", + help: "Count of proxy requests", + labelNames: ["status"], +}); + const requestsApiCount = new client.Counter({ name: "requests_api", help: "Count of API requests", -}); - -const requestsCount = new client.Counter({ - name: "requests", - help: "Count of requests", labelNames: ["status"], }); @@ -88,8 +89,8 @@ module.exports = { lastActivityUpdatingSummary, requestsWsCount, requestsWebCount, + requestsProxyCount, requestsApiCount, - requestsCount, render: function () { return client.register.metrics(); }, From 6078ba3b9e30f2bd09cc5c6ece7ebe306a2e983b Mon Sep 17 00:00:00 2001 From: Daisuke Taniwaki Date: Sat, 22 May 2021 21:12:50 +0900 Subject: [PATCH 09/19] Move metrics endpoint to API --- lib/configproxy.js | 22 ++++++++++++---------- test/api_spec.js | 18 ++++++++++++++++++ test/proxy_spec.js | 14 -------------- 3 files changed, 30 insertions(+), 24 deletions(-) diff --git a/lib/configproxy.js b/lib/configproxy.js index 705fb68d..f0aaae9f 100644 --- a/lib/configproxy.js +++ b/lib/configproxy.js @@ -160,6 +160,7 @@ class ConfigurableProxy extends EventEmitter { this.errorTarget = this.errorTarget + "/"; // ensure trailing / } this.errorPath = options.errorPath || path.join(__dirname, "error"); + if (options.disableMetrics) { this.metrics = metrics.mock; } else { @@ -329,7 +330,7 @@ class ConfigurableProxy extends EventEmitter { res.write(JSON.stringify(results)); res.end(); - this.metrics.apiRouteGetCount.inc(); + that.metrics.apiRouteGetCount.inc(); }); } @@ -347,13 +348,14 @@ class ConfigurableProxy extends EventEmitter { return this.addRoute(path, data).then(function () { res.writeHead(201); res.end(); - this.metrics.apiRouteAddCount.inc(); + that.metrics.apiRouteAddCount.inc(); }); } deleteRoutes(req, res, path) { // DELETE removes an existing route + var that = this; return this._routes.get(path).then((result) => { var p, code; if (result) { @@ -366,7 +368,7 @@ class ConfigurableProxy extends EventEmitter { return p.then(() => { res.writeHead(code); res.end(); - this.metrics.apiRouteDeleteCount.inc(); + that.metrics.apiRouteDeleteCount.inc(); }); }); } @@ -598,10 +600,6 @@ class ConfigurableProxy extends EventEmitter { handleProxyWeb(req, res) { this.handleHealthCheck(req, res); if (res.finished) return; - - if (!this.options.disableMetrics && this.handleMetrics(req, res)) { - return; - } // Proxy a web request this.metrics.requestsWebCount.inc(); return this.handleProxy("web", req, res); @@ -627,11 +625,15 @@ class ConfigurableProxy extends EventEmitter { handleApiRequest(req, res) { // Handle a request to the REST API + if (!this.options.disableMetrics) { + var p = this.handleMetrics(req, res); + if (p) { + return p; + } + } if (res) { res.on("finish", () => { - if (req.url !== "/metrics") { - this.metrics.requestsApiCount.labels(res.statusCode).inc(); - } + this.metrics.requestsApiCount.labels(res.statusCode).inc(); this.logResponse(req, res); }); } diff --git a/test/api_spec.js b/test/api_spec.js index 58fd467b..dd4dd9f8 100644 --- a/test/api_spec.js +++ b/test/api_spec.js @@ -13,6 +13,7 @@ describe("API Tests", function () { var apiPort = port + 1; var proxy; var apiUrl = "http://127.0.0.1:" + apiPort + "/api/routes"; + var metricsUrl = "http://127.0.0.1:" + apiPort + "/metrics"; var r; @@ -260,4 +261,21 @@ describe("API Tests", function () { .then(() => doReq(0)) .then(); }); + + it("GET /metrics", function (done) { + r(metricsUrl).then((body) => { + expect(body).toContain("process_cpu_user_seconds_total"); + done(); + }); + }); + + it("GET /metrics (disabled)", function (done) { + proxy.options.disableMetrics = true; + r(metricsUrl) + .then((body) => done.fail("Expected 404")) + .catch((error) => { + expect(error.statusCode).toEqual(404); + }) + .then(done); + }); }); diff --git a/test/proxy_spec.js b/test/proxy_spec.js index dff192b3..2dfbef66 100644 --- a/test/proxy_spec.js +++ b/test/proxy_spec.js @@ -431,18 +431,4 @@ describe("Proxy Tests", function () { done(); }); }); - - it("metrics request", function (done) { - r(proxyUrl + "/metrics").then((body) => { - expect(body).toContain("process_cpu_user_seconds_total"); - done(); - }); - }); - - it("disabled metrics request", function (done) { - proxy.proxy.options.disableMetrics = true; - r(proxyUrl + "/metrics") - .then((body) => done.fail("Expected 404")) - .then(done); - }); }); From 0829e60d630c81adf9fe8445ead794bd562726a1 Mon Sep 17 00:00:00 2001 From: Daisuke Taniwaki Date: Sun, 23 May 2021 01:02:56 +0900 Subject: [PATCH 10/19] Fix reference error --- lib/configproxy.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/configproxy.js b/lib/configproxy.js index f0aaae9f..010f5782 100644 --- a/lib/configproxy.js +++ b/lib/configproxy.js @@ -224,7 +224,7 @@ class ConfigurableProxy extends EventEmitter { this.proxyServer.on("upgrade", bound(this, this.handleProxyWs)); this.proxy.on("proxyRes", function (proxyRes, req, res) { - this.metrics.requestsProxyCount.labels(proxyRes.statusCode).inc(); + that.metrics.requestsProxyCount.labels(proxyRes.statusCode).inc(); }); } From e575ac9d6697b8c8dc46159dfc0d3648d66280eb Mon Sep 17 00:00:00 2001 From: Daisuke Taniwaki Date: Sun, 23 May 2021 01:05:25 +0900 Subject: [PATCH 11/19] Fix more this reference --- lib/configproxy.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/configproxy.js b/lib/configproxy.js index 010f5782..b964b783 100644 --- a/lib/configproxy.js +++ b/lib/configproxy.js @@ -632,9 +632,10 @@ class ConfigurableProxy extends EventEmitter { } } if (res) { + var that = this; res.on("finish", () => { - this.metrics.requestsApiCount.labels(res.statusCode).inc(); - this.logResponse(req, res); + that.metrics.requestsApiCount.labels(res.statusCode).inc(); + that.logResponse(req, res); }); } var args = [req, res]; From 9de2d5369b15a984dfc86a0769126f93404f30de Mon Sep 17 00:00:00 2001 From: Daisuke Taniwaki Date: Sun, 23 May 2021 01:35:04 +0900 Subject: [PATCH 12/19] Fix more this references --- lib/configproxy.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/configproxy.js b/lib/configproxy.js index b964b783..0040ed56 100644 --- a/lib/configproxy.js +++ b/lib/configproxy.js @@ -254,8 +254,8 @@ class ConfigurableProxy extends EventEmitter { var that = this; return this._routes.add(path, data).then(() => { - this.updateLastActivity(path); - this.log.info("Route added %s -> %s", path, data.target); + that.updateLastActivity(path); + that.log.info("Route added %s -> %s", path, data.target); }); } From 6b9e9ac0648d305472447ab11e5eee566bd01a8e Mon Sep 17 00:00:00 2001 From: Daisuke Taniwaki Date: Sun, 23 May 2021 01:43:13 +0900 Subject: [PATCH 13/19] Check writable instead of writableEnded --- lib/configproxy.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/configproxy.js b/lib/configproxy.js index 0040ed56..1b7fe354 100644 --- a/lib/configproxy.js +++ b/lib/configproxy.js @@ -502,7 +502,7 @@ class ConfigurableProxy extends EventEmitter { this._handleProxyErrorDefault(code, kind, req, res); return; } - if (res.writableEnded) return; // response already done + if (!res.writable) return; // response already done if (res.writeHead) res.writeHead(code, { "Content-Type": "text/html" }); if (res.write) res.write(data); if (res.end) res.end(); From 8405fe43463ef5fb5d0264a91e0f925b0d47bcd0 Mon Sep 17 00:00:00 2001 From: Daisuke Taniwaki Date: Sun, 23 May 2021 01:59:14 +0900 Subject: [PATCH 14/19] Use content type of prom-client --- lib/configproxy.js | 6 +----- lib/metrics.js | 8 ++++++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/lib/configproxy.js b/lib/configproxy.js index 1b7fe354..1ad1dba7 100644 --- a/lib/configproxy.js +++ b/lib/configproxy.js @@ -615,11 +615,7 @@ class ConfigurableProxy extends EventEmitter { handleMetrics(req, res) { if (req.url === "/metrics") { - return this.metrics.render().then((s) => { - res.writeHead(200, { "Content-Type": "text/plain; version=0.0.4" }); - res.write(s); - res.end(); - }); + return this.metrics.render(res); } } diff --git a/lib/metrics.js b/lib/metrics.js index 09537662..75178c8d 100644 --- a/lib/metrics.js +++ b/lib/metrics.js @@ -91,8 +91,12 @@ module.exports = { requestsWebCount, requestsProxyCount, requestsApiCount, - render: function () { - return client.register.metrics(); + render: function (res) { + return client.register.metrics().then((s) => { + res.writeHead(200, { "Content-Type": client.register.contentType }); + res.write(s); + res.end(); + }); }, mock, }; From 387bf143e817aa13c1d9b326df24013c41f77e21 Mon Sep 17 00:00:00 2001 From: Daisuke Taniwaki Date: Sun, 23 May 2021 12:36:12 +0900 Subject: [PATCH 15/19] Refactor metrics --- lib/configproxy.js | 4 +- lib/metrics.js | 175 ++++++++++++++++++++++++--------------------- 2 files changed, 95 insertions(+), 84 deletions(-) diff --git a/lib/configproxy.js b/lib/configproxy.js index 1ad1dba7..69be61d8 100644 --- a/lib/configproxy.js +++ b/lib/configproxy.js @@ -162,9 +162,9 @@ class ConfigurableProxy extends EventEmitter { this.errorPath = options.errorPath || path.join(__dirname, "error"); if (options.disableMetrics) { - this.metrics = metrics.mock; + this.metrics = new metrics.MockMetrics(); } else { - this.metrics = metrics; + this.metrics = new metrics.Metrics(); } if (this.options.defaultTarget) { diff --git a/lib/metrics.js b/lib/metrics.js index 75178c8d..74d7c403 100644 --- a/lib/metrics.js +++ b/lib/metrics.js @@ -1,102 +1,113 @@ "use strict"; var client = require("prom-client"); -const collectDefaultMetrics = client.collectDefaultMetrics; -collectDefaultMetrics(); -const apiRouteGetCount = new client.Counter({ - name: "api_route_get", - help: "Count of API route get requests", -}); +class Metrics { + constructor() { + this.register = new client.Registry(); + client.collectDefaultMetrics({ register: this.register }); -const apiRouteAddCount = new client.Counter({ - name: "api_route_add", - help: "Count of API route add requests", -}); - -const apiRouteDeleteCount = new client.Counter({ - name: "api_route_delete", - help: "Count of API route delete requests", -}); + this.apiRouteGetCount = new client.Counter({ + name: "api_route_get", + help: "Count of API route get requests", + registers: [this.register], + }); -const findTargetForReqSummary = new client.Summary({ - name: "find_target_for_req", - help: "Summary of find target requests", -}); + this.apiRouteAddCount = new client.Counter({ + name: "api_route_add", + help: "Count of API route add requests", + registers: [this.register], + }); -const lastActivityUpdatingSummary = new client.Summary({ - name: "last_activity_updating", - help: "Summary of last activity updating requests", -}); + this.apiRouteDeleteCount = new client.Counter({ + name: "api_route_delete", + help: "Count of API route delete requests", + registers: [this.register], + }); -const requestsWsCount = new client.Counter({ - name: "requests_ws", - help: "Count of websocket requests", -}); + this.findTargetForReqSummary = new client.Summary({ + name: "find_target_for_req", + help: "Summary of find target requests", + registers: [this.register], + }); -const requestsWebCount = new client.Counter({ - name: "requests_web", - help: "Count of web requests", -}); + this.lastActivityUpdatingSummary = new client.Summary({ + name: "last_activity_updating", + help: "Summary of last activity updating requests", + registers: [this.register], + }); -const requestsProxyCount = new client.Counter({ - name: "requests_proxy", - help: "Count of proxy requests", - labelNames: ["status"], -}); + this.requestsWsCount = new client.Counter({ + name: "requests_ws", + help: "Count of websocket requests", + registers: [this.register], + }); -const requestsApiCount = new client.Counter({ - name: "requests_api", - help: "Count of API requests", - labelNames: ["status"], -}); + this.requestsWebCount = new client.Counter({ + name: "requests_web", + help: "Count of web requests", + registers: [this.register], + }); -const mockCounter = new Proxy( - {}, - { - get(target, name) { - if (name == "inc") { - return () => {}; - } - if (name == "startTimer") { - return () => { - return () => {}; - }; - } - if (name == "labels") { - return () => { - return mockCounter; - }; - } - }, - } -); + this.requestsProxyCount = new client.Counter({ + name: "requests_proxy", + help: "Count of proxy requests", + labelNames: ["status"], + registers: [this.register], + }); -const mock = new Proxy( - {}, - { - get(target, name) { - return mockCounter; - }, + this.requestsApiCount = new client.Counter({ + name: "requests_api", + help: "Count of API requests", + labelNames: ["status"], + registers: [this.register], + }); } -); -module.exports = { - apiRouteGetCount, - apiRouteAddCount, - apiRouteDeleteCount, - findTargetForReqSummary, - lastActivityUpdatingSummary, - requestsWsCount, - requestsWebCount, - requestsProxyCount, - requestsApiCount, - render: function (res) { - return client.register.metrics().then((s) => { + render(res) { + return this.register.metrics().then((s) => { res.writeHead(200, { "Content-Type": client.register.contentType }); res.write(s); res.end(); }); - }, - mock, + } +} + +class MockMetrics { + constructor() { + return new Proxy(this, { + get(target, name) { + const mockCounter = new Proxy( + {}, + { + get(target, name) { + if (name == "inc") { + return () => {}; + } + if (name == "startTimer") { + return () => { + return () => {}; + }; + } + if (name == "labels") { + return () => { + return mockCounter; + }; + } + }, + } + ); + return mockCounter; + }, + }); + } + + render(res) { + return Promise.resolve(); + } +} + +module.exports = { + Metrics, + MockMetrics, }; From cbe294b7f6e08283aeeb32e51b5df8debe797dfb Mon Sep 17 00:00:00 2001 From: Daisuke Taniwaki Date: Sun, 23 May 2021 12:40:09 +0900 Subject: [PATCH 16/19] Fix register reference --- lib/metrics.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/metrics.js b/lib/metrics.js index 74d7c403..76da0252 100644 --- a/lib/metrics.js +++ b/lib/metrics.js @@ -66,7 +66,7 @@ class Metrics { render(res) { return this.register.metrics().then((s) => { - res.writeHead(200, { "Content-Type": client.register.contentType }); + res.writeHead(200, { "Content-Type": this.register.contentType }); res.write(s); res.end(); }); From 3b20a63887bb4898fea4e12e2674137e3a4cee72 Mon Sep 17 00:00:00 2001 From: Daisuke Taniwaki Date: Wed, 26 May 2021 00:31:16 +0900 Subject: [PATCH 17/19] Serve metrics only with metrics port option --- bin/configurable-http-proxy | 20 +++++++++++++++++--- lib/configproxy.js | 19 ++++++++++--------- 2 files changed, 27 insertions(+), 12 deletions(-) diff --git a/bin/configurable-http-proxy b/bin/configurable-http-proxy index c804084e..2a72b299 100755 --- a/bin/configurable-http-proxy +++ b/bin/configurable-http-proxy @@ -87,7 +87,8 @@ cli ) .option("--insecure", "Disable SSL cert verification") .option("--host-routing", "Use host routing (host as first level of path)") - .option("--disable-metrics", "Disable metrics endpoint") + .option("--metrics-ip ", "IP for metrics server", "0.0.0.0") + .option("--metrics-port ", "Port of metrics server. Defaults to no metrics server") .option("--log-level ", "Log level (debug, info, warn, error)", "info") .option( "--timeout ", @@ -264,8 +265,8 @@ options.headers = args.customHeader; options.timeout = args.timeout; options.proxyTimeout = args.proxyTimeout; -// prometheus options -options.disableMetrics = args.disableMetrics; +// metrics options +options.enableMetrics = !!args.metricsPort; // certs need to be provided for https redirection if (!options.ssl && options.redirectPort) { @@ -318,9 +319,14 @@ if (args.ip === "*") { listen.ip = args.ip; listen.apiIp = args.apiIp || "localhost"; listen.apiPort = args.apiPort || listen.port + 1; +listen.metricsIp = args.metricsIp || "0.0.0.0"; +listen.metricsPort = args.metricsPort; proxy.proxyServer.listen(listen.port, listen.ip); proxy.apiServer.listen(listen.apiPort, listen.apiIp); +if (listen.metricsPort) { + proxy.metricsServer.listen(listen.metricsPort, listen.metricsIp); +} log.info( "Proxying %s://%s:%s to %s", @@ -335,6 +341,14 @@ log.info( listen.apiIp || "*", listen.apiPort ); +if (listen.metricsPort) { + log.info( + "Serve metrics at %s://%s:%s/metrics", + "http", + listen.metricsIp, + listen.metricsPort + ); +} if (args.pidFile) { log.info("Writing pid %s to %s", process.pid, args.pidFile); diff --git a/lib/configproxy.js b/lib/configproxy.js index 69be61d8..ba77f5cd 100644 --- a/lib/configproxy.js +++ b/lib/configproxy.js @@ -161,10 +161,10 @@ class ConfigurableProxy extends EventEmitter { } this.errorPath = options.errorPath || path.join(__dirname, "error"); - if (options.disableMetrics) { - this.metrics = new metrics.MockMetrics(); - } else { + if (this.options.enableMetrics) { this.metrics = new metrics.Metrics(); + } else { + this.metrics = new metrics.MockMetrics(); } if (this.options.defaultTarget) { @@ -213,6 +213,12 @@ class ConfigurableProxy extends EventEmitter { this.apiServer = http.createServer(apiCallback); } + // handle metrics + if (this.options.enableMetrics) { + var metricsCallback = logErrors(that.handleMetrics); + this.metricsServer = http.createServer(metricsCallback); + } + // proxy requests separately var proxyCallback = logErrors(this.handleProxyWeb); if (this.options.ssl) { @@ -617,16 +623,11 @@ class ConfigurableProxy extends EventEmitter { if (req.url === "/metrics") { return this.metrics.render(res); } + fail(req, res, 404); } handleApiRequest(req, res) { // Handle a request to the REST API - if (!this.options.disableMetrics) { - var p = this.handleMetrics(req, res); - if (p) { - return p; - } - } if (res) { var that = this; res.on("finish", () => { From 8d5af3a883e5a8185056851dc8ba07a13eb82b0a Mon Sep 17 00:00:00 2001 From: Daisuke Taniwaki Date: Wed, 26 May 2021 00:59:44 +0900 Subject: [PATCH 18/19] Add tests --- bin/configurable-http-proxy | 7 +------ lib/testutil.js | 6 ++++++ test/api_spec.js | 18 ------------------ 3 files changed, 7 insertions(+), 24 deletions(-) diff --git a/bin/configurable-http-proxy b/bin/configurable-http-proxy index 2a72b299..d439f76a 100755 --- a/bin/configurable-http-proxy +++ b/bin/configurable-http-proxy @@ -342,12 +342,7 @@ log.info( listen.apiPort ); if (listen.metricsPort) { - log.info( - "Serve metrics at %s://%s:%s/metrics", - "http", - listen.metricsIp, - listen.metricsPort - ); + log.info("Serve metrics at %s://%s:%s/metrics", "http", listen.metricsIp, listen.metricsPort); } if (args.pidFile) { diff --git a/lib/testutil.js b/lib/testutil.js index 9717f52b..b0527080 100644 --- a/lib/testutil.js +++ b/lib/testutil.js @@ -128,12 +128,18 @@ exports.setupProxy = function (port, options, paths) { servers.push(proxy.apiServer); servers.push(proxy.proxyServer); + if (options.enableMetrics) { + servers.push(proxy.metricsServer); + } proxy.apiServer.on("listening", onlisten); proxy.proxyServer.on("listening", onlisten); addTargets(proxy, paths || ["/"], port + 2).then(function () { proxy.proxyServer.listen(port, ip); proxy.apiServer.listen(port + 1, ip); + if (options.enableMetrics) { + proxy.metricsServer.listen(port + 3, ip); + } }); return p; }; diff --git a/test/api_spec.js b/test/api_spec.js index dd4dd9f8..58fd467b 100644 --- a/test/api_spec.js +++ b/test/api_spec.js @@ -13,7 +13,6 @@ describe("API Tests", function () { var apiPort = port + 1; var proxy; var apiUrl = "http://127.0.0.1:" + apiPort + "/api/routes"; - var metricsUrl = "http://127.0.0.1:" + apiPort + "/metrics"; var r; @@ -261,21 +260,4 @@ describe("API Tests", function () { .then(() => doReq(0)) .then(); }); - - it("GET /metrics", function (done) { - r(metricsUrl).then((body) => { - expect(body).toContain("process_cpu_user_seconds_total"); - done(); - }); - }); - - it("GET /metrics (disabled)", function (done) { - proxy.options.disableMetrics = true; - r(metricsUrl) - .then((body) => done.fail("Expected 404")) - .catch((error) => { - expect(error.statusCode).toEqual(404); - }) - .then(done); - }); }); From fff977e07092f5e56dc7f1e091bf8eecb09b9ac8 Mon Sep 17 00:00:00 2001 From: Daisuke Taniwaki Date: Wed, 26 May 2021 01:02:22 +0900 Subject: [PATCH 19/19] Remove unnecessary that/this conversion --- lib/configproxy.js | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/lib/configproxy.js b/lib/configproxy.js index ba77f5cd..3b34f429 100644 --- a/lib/configproxy.js +++ b/lib/configproxy.js @@ -361,7 +361,6 @@ class ConfigurableProxy extends EventEmitter { deleteRoutes(req, res, path) { // DELETE removes an existing route - var that = this; return this._routes.get(path).then((result) => { var p, code; if (result) { @@ -374,7 +373,7 @@ class ConfigurableProxy extends EventEmitter { return p.then(() => { res.writeHead(code); res.end(); - that.metrics.apiRouteDeleteCount.inc(); + this.metrics.apiRouteDeleteCount.inc(); }); }); } @@ -629,10 +628,9 @@ class ConfigurableProxy extends EventEmitter { handleApiRequest(req, res) { // Handle a request to the REST API if (res) { - var that = this; res.on("finish", () => { - that.metrics.requestsApiCount.labels(res.statusCode).inc(); - that.logResponse(req, res); + this.metrics.requestsApiCount.labels(res.statusCode).inc(); + this.logResponse(req, res); }); } var args = [req, res];