From e2d7fa64f297ca7049860090ac9d9fa14af3c79b Mon Sep 17 00:00:00 2001 From: Steffen Date: Wed, 23 Dec 2020 20:49:02 +0100 Subject: [PATCH] added more metrics --- CHANGELOG.md | 6 ++++ package-lock.json | 21 +++++++++++++ package.json | 1 + server/index.js | 74 +++++++++++++++++++++++++++++++++++++-------- src/store/socket.js | 3 +- 5 files changed, 91 insertions(+), 14 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2fa3c3a..f898f79 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # Release Notes +## Version 2.0.3 + +- added a few more metrics + +--- + ## Version 2.0.2 - fix nomination history type not detecting travelers - fix live session domain whitelist diff --git a/package-lock.json b/package-lock.json index 9b0c29a..e2ddae5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1266,6 +1266,11 @@ "file-uri-to-path": "1.0.0" } }, + "bintrees": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/bintrees/-/bintrees-1.0.1.tgz", + "integrity": "sha1-DmVcm5wkNeqraL9AJyJtK1WjRSQ=" + }, "bluebird": { "version": "3.7.2", "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", @@ -6894,6 +6899,14 @@ "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", "dev": true }, + "prom-client": { + "version": "13.0.0", + "resolved": "https://registry.npmjs.org/prom-client/-/prom-client-13.0.0.tgz", + "integrity": "sha512-M7ZNjIO6x+2R/vjSD13yjJPjpoZA8eEwH2Bp2Re0/PvzozD7azikv+SaBtZes4Q1ca/xHjZ4RSCuTag3YZLg1A==", + "requires": { + "tdigest": "^0.1.1" + } + }, "promise-inflight": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz", @@ -8213,6 +8226,14 @@ "resolved": "https://registry.npmjs.org/tapable/-/tapable-1.1.3.tgz", "integrity": "sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA==" }, + "tdigest": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/tdigest/-/tdigest-0.1.1.tgz", + "integrity": "sha1-Ljyyw56kSeVdHmzZEReszKRYgCE=", + "requires": { + "bintrees": "1.0.1" + } + }, "terser": { "version": "4.8.0", "resolved": "https://registry.npmjs.org/terser/-/terser-4.8.0.tgz", diff --git a/package.json b/package.json index 5a25972..c715a49 100644 --- a/package.json +++ b/package.json @@ -15,6 +15,7 @@ "@fortawesome/free-solid-svg-icons": "^5.15.1", "@fortawesome/vue-fontawesome": "^0.1.10", "@vue/cli-service": "^4.5.9", + "prom-client": "^13.0.0", "sass": "^1.30.0", "sass-loader": "^8.0.2", "vue": "^2.6.12", diff --git a/server/index.js b/server/index.js index 9766048..d6bd73a 100644 --- a/server/index.js +++ b/server/index.js @@ -1,6 +1,14 @@ const fs = require("fs"); const https = require("https"); const WebSocket = require("ws"); +const client = require("prom-client"); + +// Create a Registry which registers the metrics +const register = new client.Registry(); +// Add a default label which is added to all metrics +register.setDefaultLabels({ + app: "clocktower-online" +}); const PING_INTERVAL = 30000; // 30 seconds @@ -29,6 +37,49 @@ function heartbeat() { // map of channels currently in use const channels = {}; +// metrics +const metrics = { + players_concurrent: new client.Gauge({ + name: "players_concurrent", + help: "Concurrent Players", + collect() { + this.set(wss.clients.size); + } + }), + channels_concurrent: new client.Gauge({ + name: "channels_concurrent", + help: "Concurrent Channels", + collect() { + this.set(Object.keys(channels).length); + } + }), + messages_incoming: new client.Counter({ + name: "messages_incoming", + help: "Incoming messages" + }), + messages_outgoing: new client.Counter({ + name: "messages_outgoing", + help: "Outgoing messages" + }), + connection_terminated_host: new client.Counter({ + name: "connection_terminated_host", + help: "Terminated connection due to host already present" + }), + connection_terminated_spam: new client.Counter({ + name: "connection_terminated_spam", + help: "Terminated connection due to message spam" + }), + connection_terminated_timeout: new client.Counter({ + name: "connection_terminated_timeout", + help: "Terminated connection due to timeout" + }) +}; + +// register metrics +for (let metric in metrics) { + register.registerMetric(metrics[metric]); +} + // a new client connects wss.on("connection", function connection(ws, req) { // url pattern: clocktower.online// @@ -48,6 +99,7 @@ wss.on("connection", function connection(ws, req) { ) { console.log(ws.channel, "duplicate host"); ws.close(1000, `The channel "${ws.channel}" already has a host`); + metrics.connection_terminated_host.inc(); return; } ws.isAlive = true; @@ -71,6 +123,7 @@ wss.on("connection", function connection(ws, req) { }); // handle message ws.on("message", function incoming(data) { + metrics.messages_incoming.inc(); // check rate limit (max 5msg/second) ws.counter++; if (ws.counter > (5 * PING_INTERVAL) / 1000) { @@ -79,6 +132,7 @@ wss.on("connection", function connection(ws, req) { 1000, "Your app seems to be malfunctioning, please clear your browser cache." ); + metrics.connection_terminated_spam.inc(); return; } const messageType = data @@ -101,6 +155,7 @@ wss.on("connection", function connection(ws, req) { dataToPlayer[client.playerId] ) { client.send(JSON.stringify(dataToPlayer[client.playerId])); + metrics.messages_outgoing.inc(); } }); } catch (e) { @@ -116,6 +171,7 @@ wss.on("connection", function connection(ws, req) { } else { client.send(data); } + metrics.messages_outgoing.inc(); } }); } @@ -125,7 +181,10 @@ wss.on("connection", function connection(ws, req) { // start ping interval timer const interval = setInterval(function ping() { wss.clients.forEach(function each(ws) { - if (ws.isAlive === false) return ws.terminate(); + if (ws.isAlive === false) { + metrics.connection_terminated_timeout.inc(); + return ws.terminate(); + } ws.isAlive = false; ws.pingStart = new Date().getTime(); ws.ping(noop); @@ -142,16 +201,7 @@ if (process.env.NODE_ENV !== "development") { console.log("server starting"); server.listen(8080); server.on("request", (req, res) => { - res.writeHead(200); - res.end( - `# HELP players_concurrent Concurrent players -# TYPE players_concurrent gauge -players_concurrent{app="clocktower-online"} ${wss.clients.size} - -# HELP channels_concurrent Concurrent channels -# TYPE channels_concurrent gauge -channels_concurrent{app="clocktower-online"} ${Object.keys(channels).length} -` - ); + res.setHeader("Content-Type", register.contentType); + register.metrics().then(out => res.end(out)); }); } diff --git a/src/store/socket.js b/src/store/socket.js index ab99409..abc597b 100644 --- a/src/store/socket.js +++ b/src/store/socket.js @@ -1,8 +1,7 @@ class LiveSession { constructor(store) { this._wss = "wss://live.clocktower.online:8080/"; - //this._wss = "wss://baumgart.biz:8080/"; //todo: delete this - //this._wss = "ws://localhost:8081/"; + //this._wss = "wss://localhost:8081/"; this._socket = null; this._isSpectator = true; this._gamestate = [];