diff --git a/packages/sdk-socket-server-next/package.json b/packages/sdk-socket-server-next/package.json index 2d696112b..9e2674fb0 100644 --- a/packages/sdk-socket-server-next/package.json +++ b/packages/sdk-socket-server-next/package.json @@ -51,6 +51,7 @@ "ioredis": "^5.3.2", "logform": "^2.6.0", "lru-cache": "^10.0.0", + "prom-client": "^15.1.3", "rate-limiter-flexible": "^2.3.8", "redis": "^4.6.12", "rimraf": "^4.4.0", diff --git a/packages/sdk-socket-server-next/src/index.ts b/packages/sdk-socket-server-next/src/index.ts index b719c6967..7171ca2f2 100644 --- a/packages/sdk-socket-server-next/src/index.ts +++ b/packages/sdk-socket-server-next/src/index.ts @@ -11,7 +11,7 @@ import packageJson from '../package.json'; import { isDevelopment, withAdminUI } from './config'; import { analytics, app } from './analytics-api'; import { getLogger } from './logger'; -import { extractMetrics } from './metrics'; +import { readMetrics } from './metrics'; import { configureSocketServer } from './socket-config'; import { cleanupAndExit } from './utils'; @@ -49,8 +49,7 @@ configureSocketServer(server) // Make sure to protect the endpoint to be only available within the cluster for prometheus app.get('/metrics', async (_req, res) => { res.set('Content-Type', 'text/plain'); - const metrics = extractMetrics({ ioServer }); - res.send(metrics); + res.send(await readMetrics()); }); app.get('/version', (_req, res) => { diff --git a/packages/sdk-socket-server-next/src/metrics.ts b/packages/sdk-socket-server-next/src/metrics.ts index adb6199f9..d9f23b327 100644 --- a/packages/sdk-socket-server-next/src/metrics.ts +++ b/packages/sdk-socket-server-next/src/metrics.ts @@ -1,15 +1,31 @@ -import { Server } from 'socket.io'; +import { collectDefaultMetrics, Gauge, Registry } from 'prom-client'; -export const extractMetrics = ({ ioServer }: { ioServer: Server }) => { - const totalClients = ioServer.engine.clientsCount; - let fullMetrics = `# HELP socket_io_server_total_clients Total number of connected clients\n`; - fullMetrics += `# TYPE socket_io_server_total_clients gauge\n`; - fullMetrics += `socket_io_server_total_clients ${totalClients}\n`; +const register = new Registry(); - const totalRooms = ioServer.sockets.adapter.rooms.size; - fullMetrics += `# HELP socket_io_server_total_rooms Total number of rooms\n`; - fullMetrics += `# TYPE socket_io_server_total_rooms gauge\n`; - fullMetrics += `socket_io_server_total_rooms ${totalRooms}\n`; +collectDefaultMetrics({ register }); - return fullMetrics; -}; +export async function readMetrics() { + return await register.metrics(); +} + +const socketIoServerTotalClients = new Gauge({ + name: 'socket_io_server_total_clients', + help: 'Total number of connected clients', + labelNames: [], + registers: [register], +}); + +const socketIoServerTotalRooms = new Gauge({ + name: 'socket_io_server_total_rooms', + help: 'Total number of rooms', + labelNames: [], + registers: [register], +}); + +export function setSocketIoServerTotalClients(count: number) { + socketIoServerTotalClients.set(count); +} + +export function setSocketIoServerTotalRooms(count: number) { + socketIoServerTotalRooms.set(count); +} diff --git a/packages/sdk-socket-server-next/src/socket-config.ts b/packages/sdk-socket-server-next/src/socket-config.ts index 5e773b45b..fa674c92e 100644 --- a/packages/sdk-socket-server-next/src/socket-config.ts +++ b/packages/sdk-socket-server-next/src/socket-config.ts @@ -20,6 +20,10 @@ import { } from './protocol/handleJoinChannel'; import { handleMessage, MessageParams } from './protocol/handleMessage'; import { handlePing } from './protocol/handlePing'; +import { + setSocketIoServerTotalClients, + setSocketIoServerTotalRooms, +} from './metrics'; const logger = getLogger(); @@ -68,6 +72,8 @@ export const configureSocketServer = async ( }, }); + watchSocketIoServerMetrics(io); + io.of('/').adapter.on('join-room', async (roomId, socketId) => { logger.debug(`'join-room' socket ${socketId} has joined room ${roomId}`); if (!validate(roomId)) { @@ -357,3 +363,10 @@ export const configureSocketServer = async ( return io; }; + +function watchSocketIoServerMetrics(io: Server) { + setInterval(() => { + setSocketIoServerTotalClients(io.engine.clientsCount); + setSocketIoServerTotalRooms(io.sockets.adapter.rooms.size); + }, 5_000); +} diff --git a/yarn.lock b/yarn.lock index 406207b7a..d88c1fa81 100644 --- a/yarn.lock +++ b/yarn.lock @@ -10305,6 +10305,7 @@ __metadata: lru-cache: ^10.0.0 nodemon: ^3.1.0 prettier: ^2.8.8 + prom-client: ^15.1.3 rate-limiter-flexible: ^2.3.8 redis: ^4.6.12 rimraf: ^4.4.0 @@ -11204,6 +11205,13 @@ __metadata: languageName: node linkType: hard +"@opentelemetry/api@npm:^1.4.0": + version: 1.9.0 + resolution: "@opentelemetry/api@npm:1.9.0" + checksum: 9e88e59d53ced668f3daaecfd721071c5b85a67dd386f1c6f051d1be54375d850016c881f656ffbe9a03bedae85f7e89c2f2b635313f9c9b195ad033cdc31020 + languageName: node + linkType: hard + "@parcel/watcher-android-arm64@npm:2.3.0": version: 2.3.0 resolution: "@parcel/watcher-android-arm64@npm:2.3.0" @@ -22117,6 +22125,13 @@ __metadata: languageName: node linkType: hard +"bintrees@npm:1.0.2": + version: 1.0.2 + resolution: "bintrees@npm:1.0.2" + checksum: 56a52b7d3634e30002b1eda740d2517a22fa8e9e2eb088e919f37c030a0ed86e364ab59e472fc770fc8751308054bb1c892979d150e11d9e11ac33bcc1b5d16e + languageName: node + linkType: hard + "bl@npm:^4.0.3, bl@npm:^4.1.0": version: 4.1.0 resolution: "bl@npm:4.1.0" @@ -41190,6 +41205,16 @@ __metadata: languageName: node linkType: hard +"prom-client@npm:^15.1.3": + version: 15.1.3 + resolution: "prom-client@npm:15.1.3" + dependencies: + "@opentelemetry/api": ^1.4.0 + tdigest: ^0.1.1 + checksum: 9a57f3c16f39aa9a03da021883a4231c0bb56fc9d02f6ef9c28f913379f275640a5a33b98d9946ebf53c71011a29b580e9d2d6e3806cb1c229a3f59c65993968 + languageName: node + linkType: hard + "promise-inflight@npm:^1.0.1": version: 1.0.1 resolution: "promise-inflight@npm:1.0.1" @@ -46618,6 +46643,15 @@ __metadata: languageName: node linkType: hard +"tdigest@npm:^0.1.1": + version: 0.1.2 + resolution: "tdigest@npm:0.1.2" + dependencies: + bintrees: 1.0.2 + checksum: 44de8246752b6f8c2924685f969fd3d94c36949f22b0907e99bef2b2220726dd8467f4730ea96b06040b9aa2587c0866049640039d1b956952dfa962bc2075a3 + languageName: node + linkType: hard + "telejson@npm:^6.0.8": version: 6.0.8 resolution: "telejson@npm:6.0.8"