add prometheus metrics to bridge
This commit is contained in:
parent
7ba96a905b
commit
4985e46ea4
8 changed files with 70 additions and 0 deletions
|
@ -51,6 +51,10 @@ LOG_WEBHOOK=
|
||||||
# BasicAuth or a different form of authentication.
|
# BasicAuth or a different form of authentication.
|
||||||
BOT_METRICS_PORT=
|
BOT_METRICS_PORT=
|
||||||
|
|
||||||
|
# Same as above, but for the bridge service.
|
||||||
|
# Make sure the ports don't overlap!
|
||||||
|
BRIDGE_METRICS_PORT=
|
||||||
|
|
||||||
# Optional: Set this to a channel ID if you
|
# Optional: Set this to a channel ID if you
|
||||||
# want Prometheus metrics to return `msg_ping`.
|
# want Prometheus metrics to return `msg_ping`.
|
||||||
# The bot will regularly send a message in that
|
# The bot will regularly send a message in that
|
||||||
|
|
|
@ -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",
|
||||||
"revolt-api": "^0.5.3-rc.8",
|
"revolt-api": "^0.5.3-rc.8",
|
||||||
"smart-replace": "^1.0.2",
|
"smart-replace": "^1.0.2",
|
||||||
"ulid": "^2.3.0"
|
"ulid": "^2.3.0"
|
||||||
|
|
|
@ -9,6 +9,7 @@ import FormData from 'form-data';
|
||||||
import { discordFetchUser, revoltFetchMessage } from "../util";
|
import { discordFetchUser, revoltFetchMessage } from "../util";
|
||||||
import { TextChannel } from "discord.js";
|
import { TextChannel } from "discord.js";
|
||||||
import { smartReplace } from "smart-replace";
|
import { smartReplace } from "smart-replace";
|
||||||
|
import { metrics } from "../metrics";
|
||||||
|
|
||||||
const MAX_BRIDGED_FILE_SIZE = 8_000_000; // 8 MB
|
const MAX_BRIDGED_FILE_SIZE = 8_000_000; // 8 MB
|
||||||
const RE_MENTION_USER = /<@!*[0-9]+>/g;
|
const RE_MENTION_USER = /<@!*[0-9]+>/g;
|
||||||
|
@ -31,6 +32,7 @@ client.on('messageDelete', async message => {
|
||||||
if (!targetMsg) return logger.debug(`Discord: Could not fetch message from Revolt`);
|
if (!targetMsg) return logger.debug(`Discord: Could not fetch message from Revolt`);
|
||||||
|
|
||||||
await targetMsg.delete();
|
await targetMsg.delete();
|
||||||
|
metrics.messages.inc({ source: 'discord', type: 'delete' });
|
||||||
} catch(e) {
|
} catch(e) {
|
||||||
console.error(e);
|
console.error(e);
|
||||||
}
|
}
|
||||||
|
@ -57,6 +59,7 @@ client.on('messageUpdate', async (oldMsg, newMsg) => {
|
||||||
if (!targetMsg) return logger.debug(`Discord: Could not fetch message from Revolt`);
|
if (!targetMsg) return logger.debug(`Discord: Could not fetch message from Revolt`);
|
||||||
|
|
||||||
await targetMsg.edit({ content: newMsg.content ? await renderMessageBody(newMsg.content) : undefined });
|
await targetMsg.edit({ content: newMsg.content ? await renderMessageBody(newMsg.content) : undefined });
|
||||||
|
metrics.messages.inc({ source: 'discord', type: 'edit' });
|
||||||
} catch(e) {
|
} catch(e) {
|
||||||
console.error(e);
|
console.error(e);
|
||||||
}
|
}
|
||||||
|
@ -182,6 +185,8 @@ client.on('messageCreate', async message => {
|
||||||
$set: { "revolt.messageId": res.data._id },
|
$set: { "revolt.messageId": res.data._id },
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
metrics.messages.inc({ source: 'discord', type: 'create' });
|
||||||
})
|
})
|
||||||
.catch(async e => {
|
.catch(async e => {
|
||||||
console.error(`Failed to send message`, e.response.data);
|
console.error(`Failed to send message`, e.response.data);
|
||||||
|
|
|
@ -24,6 +24,7 @@ for (const v of [ 'REVOLT_TOKEN', 'DISCORD_TOKEN', 'DB_STRING' ]) {
|
||||||
}
|
}
|
||||||
|
|
||||||
(async () => {
|
(async () => {
|
||||||
|
import('./metrics');
|
||||||
const [ revolt, discord ] = await Promise.allSettled([
|
const [ revolt, discord ] = await Promise.allSettled([
|
||||||
loginRevolt(),
|
loginRevolt(),
|
||||||
loginDiscord(),
|
loginDiscord(),
|
||||||
|
|
32
bridge/src/metrics.ts
Normal file
32
bridge/src/metrics.ts
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
import prom from 'prom-client';
|
||||||
|
import http from 'http';
|
||||||
|
import { logger } from '.';
|
||||||
|
|
||||||
|
const PORT = Number(process.env.BRIDGE_METRICS_PORT);
|
||||||
|
|
||||||
|
prom.collectDefaultMetrics({ prefix: 'automod_bridge_' });
|
||||||
|
|
||||||
|
const metrics = {
|
||||||
|
messages: new prom.Counter({ name: 'messages', help: 'Bridged message events', labelNames: [ 'source', 'type' ] }),
|
||||||
|
}
|
||||||
|
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
server.listen(PORT, () => logger.done(`Prometheus metrics ready`));
|
||||||
|
}
|
||||||
|
|
||||||
|
export { metrics }
|
|
@ -6,6 +6,7 @@ import GenericEmbed from "../types/GenericEmbed";
|
||||||
import { SendableEmbed } from "revolt-api";
|
import { SendableEmbed } from "revolt-api";
|
||||||
import { clipText, discordFetchMessage, revoltFetchUser } from "../util";
|
import { clipText, discordFetchMessage, revoltFetchUser } from "../util";
|
||||||
import { smartReplace } from "smart-replace";
|
import { smartReplace } from "smart-replace";
|
||||||
|
import { metrics } from "../metrics";
|
||||||
|
|
||||||
const RE_MENTION_USER = /<@[0-9A-HJ-KM-NP-TV-Z]{26}>/g;
|
const RE_MENTION_USER = /<@[0-9A-HJ-KM-NP-TV-Z]{26}>/g;
|
||||||
const RE_MENTION_CHANNEL = /<#[0-9A-HJ-KM-NP-TV-Z]{26}>/g;
|
const RE_MENTION_CHANNEL = /<#[0-9A-HJ-KM-NP-TV-Z]{26}>/g;
|
||||||
|
@ -31,8 +32,10 @@ client.on('message/delete', async id => {
|
||||||
const client = new WebhookClient({ id: bridgeCfg.discordWebhook.id, token: bridgeCfg.discordWebhook.token });
|
const client = new WebhookClient({ id: bridgeCfg.discordWebhook.id, token: bridgeCfg.discordWebhook.token });
|
||||||
await client.deleteMessage(bridgedMsg.discord.messageId);
|
await client.deleteMessage(bridgedMsg.discord.messageId);
|
||||||
client.destroy();
|
client.destroy();
|
||||||
|
metrics.messages.inc({ source: 'revolt', type: 'delete' });
|
||||||
} else if (targetMsg.deletable) {
|
} else if (targetMsg.deletable) {
|
||||||
targetMsg.delete();
|
targetMsg.delete();
|
||||||
|
metrics.messages.inc({ source: 'revolt', type: 'delete' });
|
||||||
} else logger.debug(`Revolt: Unable to delete Discord message`);
|
} else logger.debug(`Revolt: Unable to delete Discord message`);
|
||||||
} catch(e) {
|
} catch(e) {
|
||||||
console.error(e);
|
console.error(e);
|
||||||
|
@ -61,6 +64,8 @@ client.on('message/update', async message => {
|
||||||
const client = new WebhookClient({ id: bridgeCfg.discordWebhook.id, token: bridgeCfg.discordWebhook.token });
|
const client = new WebhookClient({ id: bridgeCfg.discordWebhook.id, token: bridgeCfg.discordWebhook.token });
|
||||||
await client.editMessage(targetMsg, { content: await renderMessageBody(message.content), allowedMentions: { parse: [ ] } });
|
await client.editMessage(targetMsg, { content: await renderMessageBody(message.content), allowedMentions: { parse: [ ] } });
|
||||||
client.destroy();
|
client.destroy();
|
||||||
|
|
||||||
|
metrics.messages.inc({ source: 'revolt', type: 'edit' });
|
||||||
} catch(e) { console.error(e) }
|
} catch(e) { console.error(e) }
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -203,6 +208,8 @@ client.on('message', async message => {
|
||||||
"discord.messageId": res.id
|
"discord.messageId": res.id
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
metrics.messages.inc({ source: 'revolt', type: 'create' });
|
||||||
})
|
})
|
||||||
.catch(async e => {
|
.catch(async e => {
|
||||||
console.error('Failed to execute webhook:', e?.response?.data ?? e);
|
console.error('Failed to execute webhook:', e?.response?.data ?? e);
|
||||||
|
|
|
@ -158,6 +158,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"
|
||||||
|
@ -464,6 +469,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"
|
||||||
|
@ -532,6 +544,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"
|
||||||
|
|
||||||
tiny-glob@^0.2.9:
|
tiny-glob@^0.2.9:
|
||||||
version "0.2.9"
|
version "0.2.9"
|
||||||
resolved "https://registry.yarnpkg.com/tiny-glob/-/tiny-glob-0.2.9.tgz#2212d441ac17928033b110f8b3640683129d31e2"
|
resolved "https://registry.yarnpkg.com/tiny-glob/-/tiny-glob-0.2.9.tgz#2212d441ac17928033b110f8b3640683129d31e2"
|
||||||
|
|
|
@ -52,6 +52,7 @@ services:
|
||||||
- DISCORD_TOKEN=${BOT_TOKEN_DISCORD}
|
- DISCORD_TOKEN=${BOT_TOKEN_DISCORD}
|
||||||
- DB_STRING=mongodb://mogus:${DB_PASS}@mongo:27017/admin
|
- DB_STRING=mongodb://mogus:${DB_PASS}@mongo:27017/admin
|
||||||
- NODE_ENV=production
|
- NODE_ENV=production
|
||||||
|
- BRIDGE_METRICS_PORT
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
depends_on:
|
depends_on:
|
||||||
- mongo
|
- mongo
|
||||||
|
|
Loading…
Reference in a new issue