Skip to content

Commit

Permalink
feat: debugger module for dumping logs in guild
Browse files Browse the repository at this point in the history
Signed-off-by: onerandomusername <genericusername414+git@gmail.com>
  • Loading branch information
onerandomusername committed Dec 2, 2021
1 parent a20721d commit ce0abcc
Showing 1 changed file with 143 additions and 0 deletions.
143 changes: 143 additions & 0 deletions modmail/extensions/debug.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
"""
Useful commands for debugging built in bot issues.
Often a problem is a configuration issue, this cog will help determine issues.
"""

import logging
import typing

import discord
from discord.ext import commands
from discord.ext.commands import Context

import modmail
from modmail.bot import ModmailBot
from modmail.log import ModmailLogger
from modmail.utils.cogs import BotModes, ExtMetadata, ModmailCog
from modmail.utils.extensions import BOT_MODE
from modmail.utils.pagination import ButtonPaginator


logger: ModmailLogger = logging.getLogger(__name__)

EXT_METADATA = ExtMetadata()

EXTRAS_DEBUG_KEY = "only_if_cog_debug"


class AlreadyInModeError(Exception):
"""Raised if the cog is already in a mode."""

pass


class DebugCog(ModmailCog, name="Debugger"):
"""Debug commands."""

def __init__(self, bot: ModmailBot):
self.bot = bot
self.enable_debug_commands = bool(BOT_MODE & BotModes.DEVELOP.value)
self.enable_or_disable_commands(self.enable_debug_commands, force=True)

def enable_or_disable_commands(self, new_status: bool = None, *, force: bool = False) -> bool:
"""Enable or disable debug only commands."""
if not force and (new_status == self.enable_debug_commands):
raise AlreadyInModeError(new_status)
elif new_status is not None:
self.enable_debug_commands = new_status
else:
self.enable_debug_commands = not self.enable_debug_commands

for com in self.walk_commands():
if com.extras.get(EXTRAS_DEBUG_KEY, False):
com.enabled = self.enable_debug_commands
return self.enable_debug_commands

@commands.group(invoke_without_command=True)
async def debug(self, ctx: Context, enable_or_disable: bool = None) -> None:
"""Commands to show logs and debug portions of the bot."""
if enable_or_disable is not None:
print(enable_or_disable)
if enable_or_disable:
self.enable_or_disable_commands(True)
msg = "Enabled the debugger commands."
else:
self.enable_or_disable_commands(False)
msg = "Disabled the debugger commands."
await ctx.send(msg)
return

await ctx.send(self.enable_debug_commands)

@staticmethod
def get_logs(tail_lines: int = 200, lines_per_page: int = 10) -> typing.List[str]:
"""Get a list of the tail logs."""
logs = []

pages = tail_lines // lines_per_page
if tail_lines < lines_per_page:
pages = 1

try:
f = open(modmail.log_file)
all_logs = f.read()
finally:
f.close()
# get the last lines on the code
pos = len(all_logs)
for _ in range(tail_lines):
if (nl_pos := all_logs.rfind("\n", None, pos)) == -1:
break
pos = nl_pos

# split away the useless section
all_logs = all_logs[pos:]
for _ in range(pages):
slice_pos = -1
for _ in range(lines_per_page):
if (
(inital_slice_pos := all_logs.find("\n", slice_pos + 1)) == -1
) or slice_pos == inital_slice_pos:
break
slice_pos = inital_slice_pos
if not len(to_append := all_logs[:slice_pos]) > 0:
continue
logs.append(to_append)
all_logs = all_logs[slice_pos:]

print(len(logs))
return logs

@debug.command(name="logs", aliases=("log",), extras={EXTRAS_DEBUG_KEY: True})
async def logs(self, ctx: Context) -> None:
"""Paginate through the last 10 pages of logs."""
logs = self.get_logs()
await ButtonPaginator.paginate(
logs,
ctx.message,
title="**Modmail Logs**",
prefix="```prolog\n",
suffix="```",
embed=None,
max_size=2000,
)

@debug.command(name="dump", extras={EXTRAS_DEBUG_KEY: True})
async def dump_logs(self, ctx: Context) -> None:
"""Dump the log file in the chat."""
logger.info(f"{ctx.author!s} requested the logs")
async with ctx.typing():
with open(modmail.log_file, "rb") as f:
file = discord.File(f, filename="modmail-logs.prolog")

await ctx.send(
"Please share this file with the developers. Do not share this with anyone else, "
"as there may be sensitive information in this file.",
file=file,
)


def setup(bot: ModmailBot) -> None:
"""Add the debug cog to the bot."""
bot.add_cog(DebugCog(bot))

0 comments on commit ce0abcc

Please sign in to comment.