From c7babfd6ff4cc0214194fbfd4e429e61cefd3d86 Mon Sep 17 00:00:00 2001 From: Cromatin Date: Fri, 18 Oct 2024 19:08:07 +0200 Subject: [PATCH] Added debug app command to get general information Updated portal to store additional data --- src/cogs/debug.py | 46 +++++++++++++++++++++++++++++++++++++++++++++ src/main.py | 45 +++++++++++++++++++++++++++++++++++++------- src/utils/portal.py | 17 +++++++++++------ 3 files changed, 95 insertions(+), 13 deletions(-) create mode 100644 src/cogs/debug.py diff --git a/src/cogs/debug.py b/src/cogs/debug.py new file mode 100644 index 0000000..b7e7378 --- /dev/null +++ b/src/cogs/debug.py @@ -0,0 +1,46 @@ +import discord +from discord import app_commands +from discord.ext import commands +from cogs.base_cog import Base_Cog +import logging +from utils.portal import Portal +from datetime import datetime +from utils.datetime_tools import get_elapsed_time_big +from utils.logger.decorator import log_command_execution + +class Debug_Command(Base_Cog): + def __init__(self, bot:commands.Bot): + self.__bot = bot + super().__init__(logging.getLogger("cmds.debug")) + + @app_commands.command(name = "debug", description = "Provides debug informations about the bot, useful for troubleshooting") + @log_command_execution + async def debug(self, ctx:discord.Interaction): + portal:Portal = Portal.instance() + embed = discord.Embed(title="Debug Information") + + embed.add_field(name="Version", + value=f"`{portal.PROGRAM_VERSION}`", + inline=True) + embed.add_field(name="Uptime", + value=f"{get_elapsed_time_big(datetime.now().timestamp() - portal.STARTUP_TIMESTAMP)}", + inline=True) + embed.add_field(name="Bot Owner", + value=f"<@{portal.bot_config['DISCORD']['OWNER_ID']}>", + inline=True) + embed.add_field(name="Latency to Gateway", + value=f"{round(self.__bot.latency * 1000, 2)}ms", + inline=True) + embed.add_field(name="Application ID", + value=f"{self.__bot.application_id}", + inline=True) + embed.add_field(name="Number of Guilds", + value=f"{len(self.__bot.guilds)}", + inline=True) + embed.add_field(name = "Number of executed commands", value=f"Total: {portal.no_executed_commands}\nSucceeded: {portal.no_succeeded_commands}\nFailed: {portal.no_failed_commands}") + + await ctx.response.send_message(embed=embed) + + +async def setup(bot:commands.Bot): + await bot.add_cog(Debug_Command(bot)) \ No newline at end of file diff --git a/src/main.py b/src/main.py index a2563ea..4554677 100644 --- a/src/main.py +++ b/src/main.py @@ -17,6 +17,8 @@ import re import sys import traceback from utils.portal import Portal +import asyncio +from typing import Union source_path = Path(__file__).resolve() base_path = source_path.parents[1] @@ -28,13 +30,37 @@ intents.messages = True class MyBot(commands.Bot): def __init__(self): super().__init__(command_prefix=None, help_command=None, intents=intents) + self.__portal:Portal + + def set_portal(self, portal:Portal): + self.__portal = portal async def setup_hook(self): # Register cogs to handle commands - for cog_name in ["about", "reload"]: + for cog_name in ["about", "reload", "debug"]: await self.load_extension(f"cogs.{cog_name}") await self.tree.sync() + async def on_app_command_completion(self, interaction: discord.Interaction, command: Union[discord.app_commands.Command, discord.app_commands.ContextMenu]): + """Called when a `app_commands.Command` or `app_commands.ContextMenu` has successfully completed without error.""" + self.__portal.no_succeeded_commands += 1 + print("Command succeeded") + + async def on_interaction(self, interaction: discord.Interaction): + """Called when an interaction happened.""" + match interaction.type.name: + case discord.InteractionType.application_command.name: + print("Interaction with bot", interaction.command.name) + self.__portal.no_executed_commands += 1 + case discord.InteractionType.ping.name: + print("App got pinged by discord") + case discord.InteractionType.autocomplete.name: + print("Interaction with autocomplete") + case discord.InteractionType.modal_submit.name: + print("Modal interaction submitted") + case discord.InteractionType.component.name: + print("Component interaction") + bot = MyBot() bot_config = Advanced_ConfigParser(Path.joinpath(base_path, "config", "bot.ini")) if re.match(r'[A-Za-z\d]{24}\.[\w-]{6}\.[\w-]{27}', bot_config["DISCORD"]["TOKEN"]): @@ -50,15 +76,20 @@ else: async def on_ready(): app_logger.info(f"Successfully logged in (after {get_elapsed_time_smal(datetime.now().timestamp() - startup)}) as {bot.user}") -@bot.tree.error -async def on_app_command_error(ctx, error): - # Traceback für mehr Informationen zum Fehler - print('Ignoring exception in command {}:'.format(ctx.command), file=sys.stderr) - traceback.print_exception(type(error), error, error.__traceback__) - # Execute some housekeeping actions portal = Portal.instance() portal.bot_config = bot_config +portal.STARTUP_TIMESTAMP = startup +bot.set_portal(portal) + +# Setup handlers to handle states of command execution +@bot.tree.error +async def on_app_command_error(ctx:discord.Interaction, error): + """Executed when exception during command execution occurs""" + print('Ignoring exception in command {}:'.format(ctx.command), file=sys.stderr) + traceback.print_exception(type(error), error, error.__traceback__) + + portal.no_failed_commands += 1 try: bot.run(bot_config["DISCORD"]["TOKEN"], log_handler = None) diff --git a/src/utils/portal.py b/src/utils/portal.py index 2fb4044..59ccc7d 100644 --- a/src/utils/portal.py +++ b/src/utils/portal.py @@ -1,6 +1,11 @@ -from utils.singleton import Singleton - -@Singleton -class Portal: - PROGRAM_VERSION = "0.1" - bot_config = None \ No newline at end of file +from utils.singleton import Singleton +from utils.adv_configparser import Advanced_ConfigParser + +@Singleton +class Portal: + PROGRAM_VERSION = "0.1" + bot_config:Advanced_ConfigParser = None + STARTUP_TIMESTAMP:float = None + no_executed_commands:int = 0 + no_succeeded_commands:int = 0 + no_failed_commands:int = 0 \ No newline at end of file