add prom metrics
This commit is contained in:
parent
8df3041449
commit
5c7d3bedd8
4 changed files with 57 additions and 9 deletions
|
@ -1,7 +1,8 @@
|
||||||
{
|
{
|
||||||
"ports": {
|
"ports": {
|
||||||
"http": 39194,
|
"http": 39194,
|
||||||
"ws": 39195
|
"ws": 39195,
|
||||||
|
"metrics": 9100
|
||||||
},
|
},
|
||||||
"session": {
|
"session": {
|
||||||
"validity": 86400,
|
"validity": 86400,
|
||||||
|
|
|
@ -20,6 +20,9 @@ import CreateEditPartyData from "./interfaces/CreateEditPartyData";
|
||||||
import JoinPartyData from "./interfaces/JoinPartyData";
|
import JoinPartyData from "./interfaces/JoinPartyData";
|
||||||
import IdData from "./interfaces/IdData";
|
import IdData from "./interfaces/IdData";
|
||||||
import Party from "./objects/Party";
|
import Party from "./objects/Party";
|
||||||
|
import SimpleProm from "simple-prom";
|
||||||
|
import Gauge from "simple-prom/lib/objects/Gauge";
|
||||||
|
import Counter from "simple-prom/lib/objects/Counter";
|
||||||
|
|
||||||
Console.customHeader(`MultiProbe server started at ${new Date()}`);
|
Console.customHeader(`MultiProbe server started at ${new Date()}`);
|
||||||
|
|
||||||
|
@ -27,6 +30,26 @@ const users = new FunkyArray<string, RemoteUser>();
|
||||||
|
|
||||||
new Database(Config.database.address, Config.database.port, Config.database.username, Config.database.password, Config.database.name);
|
new Database(Config.database.address, Config.database.port, Config.database.username, Config.database.password, Config.database.name);
|
||||||
|
|
||||||
|
const metrics = SimpleProm.init({
|
||||||
|
selfHost: true,
|
||||||
|
selfHostPort: Config.ports.metrics ?? 9100
|
||||||
|
});
|
||||||
|
|
||||||
|
const webSessions = metrics.addMetric(new Gauge("multiprobe_web_sessions"));
|
||||||
|
webSessions.setHelpText("Number of valid web sessions");
|
||||||
|
|
||||||
|
const onlineUsers = metrics.addMetric(new Gauge("multiprobe_open_connections"));
|
||||||
|
onlineUsers.setHelpText("Number of connections to the websocket");
|
||||||
|
|
||||||
|
const onlineUsersUnique = metrics.addMetric(new Gauge("multiprobe_unique_connections"));
|
||||||
|
onlineUsersUnique.setHelpText("Number of unique user connections to the websocket");
|
||||||
|
|
||||||
|
const dataIn = metrics.addMetric(new Counter("multiprobe_data_in"));
|
||||||
|
dataIn.setHelpText("Data received by the server in bytes");
|
||||||
|
|
||||||
|
const dataOut = metrics.addMetric(new Counter("multiprobe_data_out"));
|
||||||
|
dataOut.setHelpText("Data sent by the server in bytes");
|
||||||
|
|
||||||
// Web stuff
|
// Web stuff
|
||||||
|
|
||||||
const sessions = new FunkyArray<string, SessionUser>();
|
const sessions = new FunkyArray<string, SessionUser>();
|
||||||
|
@ -38,6 +61,7 @@ const sessionExpiryInterval = setInterval(() => {
|
||||||
sessions.remove(key);
|
sessions.remove(key);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
webSessions.Value = sessions.length;
|
||||||
}, 3600000);
|
}, 3600000);
|
||||||
|
|
||||||
const fastify = Fastify({
|
const fastify = Fastify({
|
||||||
|
@ -178,6 +202,7 @@ fastify.post("/account/register", async (req, res) => {
|
||||||
const key = randomBytes(Config.session.length).toString("hex");
|
const key = randomBytes(Config.session.length).toString("hex");
|
||||||
|
|
||||||
sessions.set(key, new SessionUser(user.Id, validPeriod));
|
sessions.set(key, new SessionUser(user.Id, validPeriod));
|
||||||
|
webSessions.Value = sessions.length;
|
||||||
|
|
||||||
res.setCookie("MP_SESSION", key, {
|
res.setCookie("MP_SESSION", key, {
|
||||||
path: "/",
|
path: "/",
|
||||||
|
@ -204,6 +229,7 @@ fastify.post("/account/login", async (req, res) => {
|
||||||
const key = randomBytes(Config.session.length).toString("hex");
|
const key = randomBytes(Config.session.length).toString("hex");
|
||||||
|
|
||||||
sessions.set(key, new SessionUser(user.Id, validPeriod));
|
sessions.set(key, new SessionUser(user.Id, validPeriod));
|
||||||
|
webSessions.Value = sessions.length;
|
||||||
|
|
||||||
res.setCookie("MP_SESSION", key, {
|
res.setCookie("MP_SESSION", key, {
|
||||||
path: "/",
|
path: "/",
|
||||||
|
@ -369,6 +395,19 @@ const afkInterval = setInterval(() => {
|
||||||
});
|
});
|
||||||
}, 5000);
|
}, 5000);
|
||||||
|
|
||||||
|
async function updateConnectionMetrics() {
|
||||||
|
onlineUsers.Value = users.length;
|
||||||
|
let userCount = 0;
|
||||||
|
const checkedUsers = new Array<string>();
|
||||||
|
await users.forEach(user => {
|
||||||
|
if (!checkedUsers.includes(user.username)) {
|
||||||
|
userCount++;
|
||||||
|
checkedUsers.push(user.username);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
onlineUsersUnique.Value = userCount;
|
||||||
|
}
|
||||||
|
|
||||||
websocketServer.on("connection", (socket) => {
|
websocketServer.on("connection", (socket) => {
|
||||||
const myUUID = crypto.randomUUID();
|
const myUUID = crypto.randomUUID();
|
||||||
let user:RemoteUser;
|
let user:RemoteUser;
|
||||||
|
@ -381,6 +420,7 @@ websocketServer.on("connection", (socket) => {
|
||||||
users.forEach(otherUser => otherUser.send(userLeftPacket));
|
users.forEach(otherUser => otherUser.send(userLeftPacket));
|
||||||
sendGroupUpdate(user);
|
sendGroupUpdate(user);
|
||||||
}
|
}
|
||||||
|
updateConnectionMetrics();
|
||||||
}
|
}
|
||||||
|
|
||||||
async function sendGroupUpdate(sendUser:RemoteUser, groupSend = false) {
|
async function sendGroupUpdate(sendUser:RemoteUser, groupSend = false) {
|
||||||
|
@ -421,11 +461,14 @@ websocketServer.on("connection", (socket) => {
|
||||||
|
|
||||||
socket.on("message", async (data) => {
|
socket.on("message", async (data) => {
|
||||||
const reader = createReader(Endian.LE, data as Buffer);
|
const reader = createReader(Endian.LE, data as Buffer);
|
||||||
|
dataIn.add(reader.length);
|
||||||
if (reader.length > 0 && reader.length < 1024) {
|
if (reader.length > 0 && reader.length < 1024) {
|
||||||
switch (reader.readUByte()) {
|
switch (reader.readUByte()) {
|
||||||
case MessageType.KeepAlive:
|
case MessageType.KeepAlive:
|
||||||
{
|
{
|
||||||
|
if (user !== undefined) {
|
||||||
user.lastKeepAliveTime = Date.now();
|
user.lastKeepAliveTime = Date.now();
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case MessageType.ClientDetails:
|
case MessageType.ClientDetails:
|
||||||
|
@ -462,13 +505,14 @@ websocketServer.on("connection", (socket) => {
|
||||||
usersToSend.writeUInt(otherUser.id).writeShortString(otherUser.username).writeFloat(otherUser.cursorX).writeInt(otherUser.cursorY).writeBool(otherUser.isAfk);
|
usersToSend.writeUInt(otherUser.id).writeShortString(otherUser.username).writeFloat(otherUser.cursorX).writeInt(otherUser.cursorY).writeBool(otherUser.isAfk);
|
||||||
}
|
}
|
||||||
if (dbParty) {
|
if (dbParty) {
|
||||||
user = users.set(myUUID, new RemoteUser(socket, myUUID, dbUser.Username, page, rawURL, dbUser.Id, dbParty.Id, dbParty.Name));
|
user = users.set(myUUID, new RemoteUser(socket, dataOut, myUUID, dbUser.Username, page, rawURL, dbUser.Id, dbParty.Id, dbParty.Name));
|
||||||
} else {
|
} else {
|
||||||
user = users.set(myUUID, new RemoteUser(socket, myUUID, dbUser.Username, page, rawURL, dbUser.Id, Number.MIN_VALUE, ""));
|
user = users.set(myUUID, new RemoteUser(socket, dataOut, myUUID, dbUser.Username, page, rawURL, dbUser.Id, Number.MIN_VALUE, ""));
|
||||||
}
|
}
|
||||||
sendToAllButSelf(user, createWriter(Endian.LE, 6 + dbUser.Username.length).writeByte(MessageType.ClientJoined).writeUInt(user.id).writeShortString(dbUser.Username).toBuffer());
|
sendToAllButSelf(user, createWriter(Endian.LE, 6 + dbUser.Username.length).writeByte(MessageType.ClientJoined).writeUInt(user.id).writeShortString(dbUser.Username).toBuffer());
|
||||||
user.send(usersToSend.toBuffer());
|
user.send(usersToSend.toBuffer());
|
||||||
sendGroupUpdate(user);
|
sendGroupUpdate(user);
|
||||||
|
updateConnectionMetrics();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case MessageType.CursorPos:
|
case MessageType.CursorPos:
|
||||||
|
|
|
@ -2,9 +2,7 @@ import { readFileSync } from "fs";
|
||||||
|
|
||||||
const config = JSON.parse(readFileSync("./config.json").toString());
|
const config = JSON.parse(readFileSync("./config.json").toString());
|
||||||
|
|
||||||
export default class Config {
|
export default abstract class Config {
|
||||||
public constructor() { throw new Error("Static Class"); }
|
|
||||||
|
|
||||||
public static ports:ConfigPorts = config.ports;
|
public static ports:ConfigPorts = config.ports;
|
||||||
public static session:ConfigSession = config.session;
|
public static session:ConfigSession = config.session;
|
||||||
public static githost:string = config.githost;
|
public static githost:string = config.githost;
|
||||||
|
@ -13,7 +11,8 @@ export default class Config {
|
||||||
|
|
||||||
interface ConfigPorts {
|
interface ConfigPorts {
|
||||||
http: number,
|
http: number,
|
||||||
ws: number
|
ws: number,
|
||||||
|
metrics: number
|
||||||
}
|
}
|
||||||
|
|
||||||
interface ConfigSession {
|
interface ConfigSession {
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
import IMetric from "simple-prom/lib/interfaces/IMetric";
|
||||||
import { WebSocket } from "ws";
|
import { WebSocket } from "ws";
|
||||||
|
|
||||||
export default class RemoteUser {
|
export default class RemoteUser {
|
||||||
|
@ -9,6 +10,7 @@ export default class RemoteUser {
|
||||||
public readonly username:string;
|
public readonly username:string;
|
||||||
public readonly currentURL:string;
|
public readonly currentURL:string;
|
||||||
public readonly rawURL:string = "";
|
public readonly rawURL:string = "";
|
||||||
|
private readonly dataOut:IMetric;
|
||||||
public cursorX:number = 0;
|
public cursorX:number = 0;
|
||||||
public cursorY:number = 0;
|
public cursorY:number = 0;
|
||||||
public allowedPings:number;
|
public allowedPings:number;
|
||||||
|
@ -20,13 +22,14 @@ export default class RemoteUser {
|
||||||
public isAfk:boolean;
|
public isAfk:boolean;
|
||||||
public timeLastMovedCursor: number;
|
public timeLastMovedCursor: number;
|
||||||
|
|
||||||
constructor(socket:WebSocket, connectionUUID:string, username:string, currentURL:string, rawURL:string, userId:number, groupId:number, groupName:string) {
|
constructor(socket:WebSocket, dataOut:IMetric, connectionUUID:string, username:string, currentURL:string, rawURL:string, userId:number, groupId:number, groupName:string) {
|
||||||
this.socket = socket;
|
this.socket = socket;
|
||||||
this.connectionUUID = connectionUUID;
|
this.connectionUUID = connectionUUID;
|
||||||
this.id = RemoteUser.USER_IDS++;
|
this.id = RemoteUser.USER_IDS++;
|
||||||
this.username = username;
|
this.username = username;
|
||||||
this.currentURL = currentURL;
|
this.currentURL = currentURL;
|
||||||
this.rawURL = rawURL;
|
this.rawURL = rawURL;
|
||||||
|
this.dataOut = dataOut;
|
||||||
this.allowedPings = 10;
|
this.allowedPings = 10;
|
||||||
this.lastPingReset = Date.now();
|
this.lastPingReset = Date.now();
|
||||||
this.userId = userId;
|
this.userId = userId;
|
||||||
|
@ -38,6 +41,7 @@ export default class RemoteUser {
|
||||||
}
|
}
|
||||||
|
|
||||||
send(data:Buffer) {
|
send(data:Buffer) {
|
||||||
|
this.dataOut.add(data.length);
|
||||||
this.socket.send(data);
|
this.socket.send(data);
|
||||||
}
|
}
|
||||||
}
|
}
|
Loading…
Reference in a new issue