From 57ed43b0183f130a75f6c23890d9c9907838c039 Mon Sep 17 00:00:00 2001 From: Dragory <2606411+Dragory@users.noreply.github.com> Date: Sun, 12 Sep 2021 00:17:26 +0300 Subject: [PATCH] Add rate limit logging --- backend/src/index.ts | 5 +++ .../plugins/BotControl/BotControlPlugin.ts | 2 ++ .../commands/RateLimitPerformanceCmd.ts | 36 +++++++++++++++++++ backend/src/rateLimitStats.ts | 24 +++++++++++++ 4 files changed, 67 insertions(+) create mode 100644 backend/src/plugins/BotControl/commands/RateLimitPerformanceCmd.ts create mode 100644 backend/src/rateLimitStats.ts diff --git a/backend/src/index.ts b/backend/src/index.ts index 829f89ac..6b552733 100644 --- a/backend/src/index.ts +++ b/backend/src/index.ts @@ -22,6 +22,7 @@ import { loadYamlSafely } from "./utils/loadYamlSafely"; import { DecayingCounter } from "./utils/DecayingCounter"; import { PluginNotLoadedError } from "knub/dist/plugins/PluginNotLoadedError"; import { logRestCall } from "./restCallStats"; +import { logRateLimit } from "./rateLimitStats"; if (!process.env.KEY) { // tslint:disable-next-line:no-console @@ -317,6 +318,10 @@ connect().then(async () => { startUptimeCounter(); }); + client.on(Constants.Events.RATE_LIMIT, (data) => { + logRateLimit(data); + }); + bot.initialize(); logger.info("Bot Initialized"); logger.info("Logging in..."); diff --git a/backend/src/plugins/BotControl/BotControlPlugin.ts b/backend/src/plugins/BotControl/BotControlPlugin.ts index bef25d24..9c6b0123 100644 --- a/backend/src/plugins/BotControl/BotControlPlugin.ts +++ b/backend/src/plugins/BotControl/BotControlPlugin.ts @@ -22,6 +22,7 @@ import { PluginPerformanceCmd } from "./commands/PluginPerformanceCmd"; import { AddServerFromInviteCmd } from "./commands/AddServerFromInviteCmd"; import { ChannelToServerCmd } from "./commands/ChannelToServerCmd"; import { RestPerformanceCmd } from "./commands/RestPerformanceCmd"; +import { RateLimitPerformanceCmd } from "./commands/RateLimitPerformanceCmd"; const defaultOptions = { config: { @@ -54,6 +55,7 @@ export const BotControlPlugin = zeppelinGlobalPlugin()({ EligibleCmd, PluginPerformanceCmd, RestPerformanceCmd, + RateLimitPerformanceCmd, AddServerFromInviteCmd, ChannelToServerCmd, ], diff --git a/backend/src/plugins/BotControl/commands/RateLimitPerformanceCmd.ts b/backend/src/plugins/BotControl/commands/RateLimitPerformanceCmd.ts new file mode 100644 index 00000000..fdf81993 --- /dev/null +++ b/backend/src/plugins/BotControl/commands/RateLimitPerformanceCmd.ts @@ -0,0 +1,36 @@ +import { botControlCmd } from "../types"; +import { getRateLimitStats } from "../../../rateLimitStats"; +import moment from "moment-timezone"; +import { GuildArchives } from "../../../data/GuildArchives"; +import { getBaseUrl, sendErrorMessage, sendSuccessMessage } from "../../../pluginUtils"; +import { TextChannel } from "discord.js"; + +export const RateLimitPerformanceCmd = botControlCmd({ + trigger: ["rate_limit_performance"], + permission: "can_performance", + + signature: {}, + + async run({ pluginData, message: msg, args }) { + const logItems = getRateLimitStats(); + if (logItems.length === 0) { + sendSuccessMessage(pluginData, msg.channel as TextChannel, `No rate limits hit`); + return; + } + + logItems.reverse(); + const formatted = logItems.map((item) => { + const formattedTime = moment.utc(item.timestamp).format("YYYY-MM-DD HH:mm:ss.SSS"); + return `${item.data.global ? "GLOBAL " : ""}${item.data.method} ${item.data.route} stalled for ${ + item.data.timeout + }ms`; + }); + + const fullText = `Last ${logItems.length} rate limits hit:\n\n${formatted.join("\n")}`; + + const archives = GuildArchives.getGuildInstance("0"); + const archiveId = await archives.create(fullText, moment().add(1, "hour")); + const archiveUrl = archives.getUrl(getBaseUrl(pluginData), archiveId); + msg.channel.send(`Link: ${archiveUrl}`); + }, +}); diff --git a/backend/src/rateLimitStats.ts b/backend/src/rateLimitStats.ts new file mode 100644 index 00000000..eb3c142f --- /dev/null +++ b/backend/src/rateLimitStats.ts @@ -0,0 +1,24 @@ +import { RateLimitData } from "discord.js"; + +type RateLimitLogItem = { + timestamp: number; + data: RateLimitData; +}; + +const rateLimitLog: RateLimitLogItem[] = []; + +const MAX_RATE_LIMIT_LOG_ITEMS = 100; + +export function logRateLimit(data: RateLimitData) { + rateLimitLog.push({ + timestamp: Date.now(), + data, + }); + if (rateLimitLog.length > MAX_RATE_LIMIT_LOG_ITEMS) { + rateLimitLog.splice(0, rateLimitLog.length - MAX_RATE_LIMIT_LOG_ITEMS); + } +} + +export function getRateLimitStats(): RateLimitLogItem[] { + return Array.from(rateLimitLog); +}