add basic prometheus metrics
This commit is contained in:
parent
5efcfba5c1
commit
75ad95a357
7 changed files with 115 additions and 0 deletions
13
.env.example
13
.env.example
|
@ -31,6 +31,19 @@ BOT_OWNERS=
|
||||||
# used to log certain events (bot started, etc).
|
# used to log certain events (bot started, etc).
|
||||||
LOG_WEBHOOK=
|
LOG_WEBHOOK=
|
||||||
|
|
||||||
|
# Optional: If set, enables Prometheus metrics
|
||||||
|
# on the specified port (Under /metrics).
|
||||||
|
# Note that no authentication can be configured;
|
||||||
|
# you should use a reverse proxy if you need
|
||||||
|
# BasicAuth or a different form of authentication.
|
||||||
|
BOT_METRICS_PORT=
|
||||||
|
|
||||||
|
# Optional: Set this to a channel ID if you
|
||||||
|
# want Prometheus metrics to return `msg_ping`.
|
||||||
|
# The bot will regularly send a message in that
|
||||||
|
# channel.
|
||||||
|
BOT_METRICS_MSG_PING_CHANNEL=
|
||||||
|
|
||||||
# The URL from which your API and Web app are
|
# The URL from which your API and Web app are
|
||||||
# publicly reachable. Do not add a trailing
|
# publicly reachable. Do not add a trailing
|
||||||
# slash to the URLs.
|
# slash to the URLs.
|
||||||
|
|
|
@ -22,6 +22,7 @@
|
||||||
"form-data": "^4.0.0",
|
"form-data": "^4.0.0",
|
||||||
"log75": "^2.2.0",
|
"log75": "^2.2.0",
|
||||||
"monk": "^7.3.4",
|
"monk": "^7.3.4",
|
||||||
|
"prom-client": "^14.0.1",
|
||||||
"ulid": "^2.3.0",
|
"ulid": "^2.3.0",
|
||||||
"xlsx": "^0.17.3"
|
"xlsx": "^0.17.3"
|
||||||
},
|
},
|
||||||
|
|
|
@ -10,6 +10,7 @@ import MessageCommandContext from "../../struct/MessageCommandContext";
|
||||||
import { fileURLToPath } from 'url';
|
import { fileURLToPath } from 'url';
|
||||||
import { getOwnMemberInServer, hasPermForChannel } from "../util";
|
import { getOwnMemberInServer, hasPermForChannel } from "../util";
|
||||||
import { isSudo, updateSudoTimeout } from "../commands/botadm";
|
import { isSudo, updateSudoTimeout } from "../commands/botadm";
|
||||||
|
import { metrics } from "./metrics";
|
||||||
|
|
||||||
// thanks a lot esm
|
// thanks a lot esm
|
||||||
const filename = fileURLToPath(import.meta.url);
|
const filename = fileURLToPath(import.meta.url);
|
||||||
|
@ -72,6 +73,8 @@ let commands: Command[];
|
||||||
let cmd = commands.find(c => c.name == cmdName || (c.aliases?.indexOf(cmdName!) ?? -1) > -1);
|
let cmd = commands.find(c => c.name == cmdName || (c.aliases?.indexOf(cmdName!) ?? -1) > -1);
|
||||||
if (!cmd) return;
|
if (!cmd) return;
|
||||||
|
|
||||||
|
metrics.commands.inc();
|
||||||
|
|
||||||
if (isSudo(msg.author!)) updateSudoTimeout(msg.author!);
|
if (isSudo(msg.author!)) updateSudoTimeout(msg.author!);
|
||||||
|
|
||||||
if (cmd.restrict == 'BOTOWNER' && ownerIDs.indexOf(msg.author_id) == -1) {
|
if (cmd.restrict == 'BOTOWNER' && ownerIDs.indexOf(msg.author_id) == -1) {
|
||||||
|
|
73
bot/src/bot/modules/metrics.ts
Normal file
73
bot/src/bot/modules/metrics.ts
Normal file
|
@ -0,0 +1,73 @@
|
||||||
|
import prom from 'prom-client';
|
||||||
|
import http from 'http';
|
||||||
|
import logger from '../logger';
|
||||||
|
import { client } from '../..';
|
||||||
|
import { decodeTime } from 'ulid';
|
||||||
|
|
||||||
|
const PORT = Number(process.env.BOT_METRICS_PORT);
|
||||||
|
|
||||||
|
prom.collectDefaultMetrics({ prefix: 'automod_' });
|
||||||
|
|
||||||
|
const metrics = {
|
||||||
|
commands: new prom.Counter({ name: 'commands_executed', help: 'Amount of executed commands' }),
|
||||||
|
servers: new prom.Gauge({ name: 'server_count', help: 'Amount of servers the bot is in' }),
|
||||||
|
wsPing: new prom.Gauge({ name: 'ws_ping', help: 'WebSocket ping as returned by revolt.js' }),
|
||||||
|
msgPing: new prom.Gauge({ name: 'msg_ping', help: 'Amount of time it takes for the bot to send a message' }),
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isNaN(PORT)) {
|
||||||
|
logger.info(`Enabling Prometheus metrics on :${PORT}`);
|
||||||
|
|
||||||
|
const server = new http.Server();
|
||||||
|
|
||||||
|
server.on('request', async (req, res) => {
|
||||||
|
if (req.url == '/metrics') {
|
||||||
|
res.write(await prom.register.metrics());
|
||||||
|
res.end();
|
||||||
|
} else {
|
||||||
|
res.statusCode = 404;
|
||||||
|
res.write('404 not found');
|
||||||
|
res.end();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const setServerCount = () => metrics.servers.set(client.servers.size);
|
||||||
|
|
||||||
|
client.once('ready', setServerCount);
|
||||||
|
client.on('server/update', setServerCount);
|
||||||
|
client.on('server/delete', setServerCount);
|
||||||
|
|
||||||
|
const measureLatency = async () => {
|
||||||
|
const wsPing = client.websocket.ping;
|
||||||
|
if (wsPing != undefined) metrics.wsPing.set(wsPing);
|
||||||
|
}
|
||||||
|
|
||||||
|
client.once('ready', () => {
|
||||||
|
measureLatency();
|
||||||
|
setInterval(measureLatency, 10000);
|
||||||
|
|
||||||
|
if (process.env.BOT_METRICS_MSG_PING_CHANNEL) {
|
||||||
|
logger.info('BOT_METRICS_MSG_PING_CHANNEL is set, enabling message latency measuring');
|
||||||
|
|
||||||
|
const getMsgPing = async () => {
|
||||||
|
const channel = client.channels.get(process.env.BOT_METRICS_MSG_PING_CHANNEL!);
|
||||||
|
try {
|
||||||
|
const now = Date.now();
|
||||||
|
const msg = await channel?.sendMessage('Ping?');
|
||||||
|
if (!msg) return;
|
||||||
|
|
||||||
|
const delay = decodeTime(msg._id) - now;
|
||||||
|
metrics.msgPing.set(delay);
|
||||||
|
await msg.edit({ content: `Pong! ${delay}ms` });
|
||||||
|
} catch(e) { console.error(e) }
|
||||||
|
}
|
||||||
|
|
||||||
|
getMsgPing();
|
||||||
|
setInterval(getMsgPing, 30000);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
server.listen(PORT, () => logger.done(`Prometheus metrics ready`));
|
||||||
|
}
|
||||||
|
|
||||||
|
export { metrics };
|
|
@ -31,4 +31,5 @@ export { client }
|
||||||
import('./bot/modules/tempbans');
|
import('./bot/modules/tempbans');
|
||||||
import('./bot/modules/user_scan');
|
import('./bot/modules/user_scan');
|
||||||
import('./bot/modules/api_communication');
|
import('./bot/modules/api_communication');
|
||||||
|
import('./bot/modules/metrics');
|
||||||
})();
|
})();
|
||||||
|
|
|
@ -150,6 +150,11 @@ base64-js@^1.3.1:
|
||||||
resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a"
|
resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a"
|
||||||
integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==
|
integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==
|
||||||
|
|
||||||
|
bintrees@1.0.1:
|
||||||
|
version "1.0.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/bintrees/-/bintrees-1.0.1.tgz#0e655c9b9c2435eaab68bf4027226d2b55a34524"
|
||||||
|
integrity sha1-DmVcm5wkNeqraL9AJyJtK1WjRSQ=
|
||||||
|
|
||||||
bl@^2.2.1:
|
bl@^2.2.1:
|
||||||
version "2.2.1"
|
version "2.2.1"
|
||||||
resolved "https://registry.yarnpkg.com/bl/-/bl-2.2.1.tgz#8c11a7b730655c5d56898cdc871224f40fd901d5"
|
resolved "https://registry.yarnpkg.com/bl/-/bl-2.2.1.tgz#8c11a7b730655c5d56898cdc871224f40fd901d5"
|
||||||
|
@ -498,6 +503,13 @@ process-nextick-args@~2.0.0:
|
||||||
resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2"
|
resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2"
|
||||||
integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==
|
integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==
|
||||||
|
|
||||||
|
prom-client@^14.0.1:
|
||||||
|
version "14.0.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/prom-client/-/prom-client-14.0.1.tgz#bdd9583e02ec95429677c0e013712d42ef1f86a8"
|
||||||
|
integrity sha512-HxTArb6fkOntQHoRGvv4qd/BkorjliiuO2uSWC2KC17MUTKYttWdDoXX/vxOhQdkoECEM9BBH0pj2l8G8kev6w==
|
||||||
|
dependencies:
|
||||||
|
tdigest "^0.1.1"
|
||||||
|
|
||||||
readable-stream@^2.3.5:
|
readable-stream@^2.3.5:
|
||||||
version "2.3.7"
|
version "2.3.7"
|
||||||
resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.7.tgz#1eca1cf711aef814c04f62252a36a62f6cb23b57"
|
resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.7.tgz#1eca1cf711aef814c04f62252a36a62f6cb23b57"
|
||||||
|
@ -559,6 +571,13 @@ string_decoder@~1.1.1:
|
||||||
dependencies:
|
dependencies:
|
||||||
safe-buffer "~5.1.0"
|
safe-buffer "~5.1.0"
|
||||||
|
|
||||||
|
tdigest@^0.1.1:
|
||||||
|
version "0.1.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/tdigest/-/tdigest-0.1.1.tgz#2e3cb2c39ea449e55d1e6cd91117accca4588021"
|
||||||
|
integrity sha1-Ljyyw56kSeVdHmzZEReszKRYgCE=
|
||||||
|
dependencies:
|
||||||
|
bintrees "1.0.1"
|
||||||
|
|
||||||
tr46@~0.0.3:
|
tr46@~0.0.3:
|
||||||
version "0.0.3"
|
version "0.0.3"
|
||||||
resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a"
|
resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a"
|
||||||
|
|
|
@ -19,6 +19,11 @@ services:
|
||||||
- API_WS_TOKEN=${INTERNAL_API_TOKEN}
|
- API_WS_TOKEN=${INTERNAL_API_TOKEN}
|
||||||
- WEB_UI_URL=${PUBLIC_WEB_URL}
|
- WEB_UI_URL=${PUBLIC_WEB_URL}
|
||||||
- BOT_PREFIX
|
- BOT_PREFIX
|
||||||
|
- BOT_METRICS_PORT
|
||||||
|
- BOT_METRICS_MSG_PING_CHANNEL
|
||||||
|
# Uncomment if you enabled Prometheus metrics
|
||||||
|
#ports:
|
||||||
|
# - 127.0.0.1:${BOT_METRICS_PORT}:${BOT_METRICS_PORT}
|
||||||
depends_on:
|
depends_on:
|
||||||
- mongo
|
- mongo
|
||||||
- api
|
- api
|
||||||
|
|
Loading…
Reference in a new issue