added more metrics

This commit is contained in:
Steffen 2020-12-23 20:49:02 +01:00
parent 3a5a8bfc9a
commit e2d7fa64f2
5 changed files with 91 additions and 14 deletions

View File

@ -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

21
package-lock.json generated
View File

@ -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",

View File

@ -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",

View File

@ -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/<channel>/<playerId|host>
@ -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));
});
}

View File

@ -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 = [];