feat(meta): Improve bugsplat.
This commit is contained in:
@@ -11,6 +11,7 @@ from discord.app_commands.errors import CommandInvokeError as appCommandInvokeEr
|
|||||||
from aiohttp import ClientSession
|
from aiohttp import ClientSession
|
||||||
|
|
||||||
from data import Database
|
from data import Database
|
||||||
|
from utils.lib import tabulate
|
||||||
|
|
||||||
from .config import Conf
|
from .config import Conf
|
||||||
from .logger import logging_context, log_context, log_action_stack, log_wrap, set_logging_context
|
from .logger import logging_context, log_context, log_action_stack, log_wrap, set_logging_context
|
||||||
@@ -192,7 +193,7 @@ class LionBot(Bot):
|
|||||||
pass
|
pass
|
||||||
except asyncio.TimeoutError:
|
except asyncio.TimeoutError:
|
||||||
pass
|
pass
|
||||||
except Exception:
|
except Exception as e:
|
||||||
logger.exception(
|
logger.exception(
|
||||||
f"Caught an unknown CommandInvokeError while executing: {cmd_str}",
|
f"Caught an unknown CommandInvokeError while executing: {cmd_str}",
|
||||||
extra={'action': 'BotError', 'with_ctx': True}
|
extra={'action': 'BotError', 'with_ctx': True}
|
||||||
@@ -201,10 +202,36 @@ class LionBot(Bot):
|
|||||||
error_embed = discord.Embed(title="Something went wrong!")
|
error_embed = discord.Embed(title="Something went wrong!")
|
||||||
error_embed.description = (
|
error_embed.description = (
|
||||||
"An unexpected error occurred while processing your command!\n"
|
"An unexpected error occurred while processing your command!\n"
|
||||||
"Our development team has been notified, and the issue should be fixed soon.\n"
|
"Our development team has been notified, and the issue will be addressed soon.\n"
|
||||||
"If the error persists, please contact our support team and give them the following number: "
|
"If the error persists, or you have any questions, please contact our [support team]({link}) "
|
||||||
f"`{ctx.interaction.id if ctx.interaction else ctx.message.id}`"
|
"and give them the extra details below."
|
||||||
)
|
).format(link=self.config.bot.support_guild)
|
||||||
|
details = {}
|
||||||
|
details['error'] = f"`{repr(e)}`"
|
||||||
|
if ctx.interaction:
|
||||||
|
details['interactionid'] = f"`{ctx.interaction.id}`"
|
||||||
|
if ctx.command:
|
||||||
|
details['cmd'] = f"`{ctx.command.qualified_name}`"
|
||||||
|
if ctx.author:
|
||||||
|
details['author'] = f"`{ctx.author.id}` -- `{ctx.author}`"
|
||||||
|
if ctx.guild:
|
||||||
|
details['guild'] = f"`{ctx.guild.id}` -- `{ctx.guild.name}`"
|
||||||
|
details['my_guild_perms'] = f"`{ctx.guild.me.guild_permissions.value}`"
|
||||||
|
if ctx.author:
|
||||||
|
ownerstr = ' (owner)' if ctx.author == ctx.guild.owner else ''
|
||||||
|
details['author_guild_perms'] = f"`{ctx.author.guild_permissions.value}{ownerstr}`"
|
||||||
|
if ctx.channel.type is discord.enums.ChannelType.private:
|
||||||
|
details['channel'] = "`Direct Message`"
|
||||||
|
elif ctx.channel:
|
||||||
|
details['channel'] = f"`{ctx.channel.id}` -- `{ctx.channel.name}`"
|
||||||
|
details['my_channel_perms'] = f"`{ctx.channel.permissions_for(ctx.guild.me).value}`"
|
||||||
|
if ctx.author:
|
||||||
|
details['author_channel_perms'] = f"`{ctx.channel.permissions_for(ctx.author).value}`"
|
||||||
|
details['shard'] = f"`{self.shardname}`"
|
||||||
|
details['log_stack'] = f"`{log_action_stack.get()}`"
|
||||||
|
|
||||||
|
table = '\n'.join(tabulate(*details.items()))
|
||||||
|
error_embed.add_field(name='Details', value=table)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
await ctx.error_reply(embed=error_embed)
|
await ctx.error_reply(embed=error_embed)
|
||||||
|
|||||||
@@ -1,12 +1,15 @@
|
|||||||
import logging
|
import logging
|
||||||
|
|
||||||
|
import discord
|
||||||
from discord import Interaction
|
from discord import Interaction
|
||||||
from discord.app_commands import CommandTree
|
from discord.app_commands import CommandTree
|
||||||
from discord.app_commands.errors import AppCommandError, CommandInvokeError
|
from discord.app_commands.errors import AppCommandError, CommandInvokeError
|
||||||
from discord.enums import InteractionType
|
from discord.enums import InteractionType
|
||||||
from discord.app_commands.namespace import Namespace
|
from discord.app_commands.namespace import Namespace
|
||||||
|
|
||||||
from .logger import logging_context, set_logging_context, log_wrap
|
from utils.lib import tabulate
|
||||||
|
|
||||||
|
from .logger import logging_context, set_logging_context, log_wrap, log_action_stack
|
||||||
from .errors import SafeCancellation
|
from .errors import SafeCancellation
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
@@ -17,7 +20,7 @@ class LionTree(CommandTree):
|
|||||||
super().__init__(*args, **kwargs)
|
super().__init__(*args, **kwargs)
|
||||||
self._call_tasks = set()
|
self._call_tasks = set()
|
||||||
|
|
||||||
async def on_error(self, interaction, error) -> None:
|
async def on_error(self, interaction: discord.Interaction, error) -> None:
|
||||||
try:
|
try:
|
||||||
if isinstance(error, CommandInvokeError):
|
if isinstance(error, CommandInvokeError):
|
||||||
raise error.original
|
raise error.original
|
||||||
@@ -28,6 +31,51 @@ class LionTree(CommandTree):
|
|||||||
pass
|
pass
|
||||||
except Exception:
|
except Exception:
|
||||||
logger.exception(f"Unhandled exception in interaction: {interaction}", extra={'action': 'TreeError'})
|
logger.exception(f"Unhandled exception in interaction: {interaction}", extra={'action': 'TreeError'})
|
||||||
|
if not interaction.is_expired():
|
||||||
|
splat = self.bugsplat(interaction, error)
|
||||||
|
try:
|
||||||
|
if interaction.response.is_done():
|
||||||
|
await interaction.followup.send(embed=splat, ephemeral=True)
|
||||||
|
else:
|
||||||
|
await interaction.response.send_message(embed=splat, ephemeral=True)
|
||||||
|
except discord.HTTPException:
|
||||||
|
pass
|
||||||
|
|
||||||
|
def bugsplat(self, interaction, e):
|
||||||
|
error_embed = discord.Embed(title="Something went wrong!", colour=discord.Colour.red())
|
||||||
|
error_embed.description = (
|
||||||
|
"An unexpected error occurred during this interaction!\n"
|
||||||
|
"Our development team has been notified, and the issue will be addressed soon.\n"
|
||||||
|
"If the error persists, or you have any questions, please contact our [support team]({link}) "
|
||||||
|
"and give them the extra details below."
|
||||||
|
).format(link=interaction.client.config.bot.support_guild)
|
||||||
|
details = {}
|
||||||
|
details['error'] = f"`{repr(e)}`"
|
||||||
|
details['interactionid'] = f"`{interaction.id}`"
|
||||||
|
details['interactiontype'] = f"`{interaction.type}`"
|
||||||
|
if interaction.command:
|
||||||
|
details['cmd'] = f"`{interaction.command.qualified_name}`"
|
||||||
|
if interaction.user:
|
||||||
|
details['user'] = f"`{interaction.user.id}` -- `{interaction.user}`"
|
||||||
|
if interaction.guild:
|
||||||
|
details['guild'] = f"`{interaction.guild.id}` -- `{interaction.guild.name}`"
|
||||||
|
details['my_guild_perms'] = f"`{interaction.guild.me.guild_permissions.value}`"
|
||||||
|
if interaction.user:
|
||||||
|
ownerstr = ' (owner)' if interaction.user == interaction.guild.owner else ''
|
||||||
|
details['user_guild_perms'] = f"`{interaction.user.guild_permissions.value}{ownerstr}`"
|
||||||
|
if interaction.channel.type is discord.enums.ChannelType.private:
|
||||||
|
details['channel'] = "`Direct Message`"
|
||||||
|
elif interaction.channel:
|
||||||
|
details['channel'] = f"`{interaction.channel.id}` -- `{interaction.channel.name}`"
|
||||||
|
details['my_channel_perms'] = f"`{interaction.channel.permissions_for(interaction.guild.me).value}`"
|
||||||
|
if interaction.user:
|
||||||
|
details['user_channel_perms'] = f"`{interaction.channel.permissions_for(interaction.user).value}`"
|
||||||
|
details['shard'] = f"`{interaction.client.shardname}`"
|
||||||
|
details['log_stack'] = f"`{log_action_stack.get()}`"
|
||||||
|
|
||||||
|
table = '\n'.join(tabulate(*details.items()))
|
||||||
|
error_embed.add_field(name='Details', value=table)
|
||||||
|
return error_embed
|
||||||
|
|
||||||
def _from_interaction(self, interaction: Interaction) -> None:
|
def _from_interaction(self, interaction: Interaction) -> None:
|
||||||
@log_wrap(context=f"iid: {interaction.id}", isolate=False)
|
@log_wrap(context=f"iid: {interaction.id}", isolate=False)
|
||||||
|
|||||||
@@ -230,9 +230,20 @@ class LeoUI(View):
|
|||||||
)
|
)
|
||||||
except Exception:
|
except Exception:
|
||||||
logger.exception(
|
logger.exception(
|
||||||
f"Unhandled interaction exception occurred in item {item!r} of LeoUI {self!r}",
|
f"Unhandled interaction exception occurred in item {item!r} of LeoUI {self!r} from interaction: "
|
||||||
|
f"{interaction.data}",
|
||||||
extra={'with_ctx': True, 'action': 'UIError'}
|
extra={'with_ctx': True, 'action': 'UIError'}
|
||||||
)
|
)
|
||||||
|
# Explicitly handle the bugsplat ourselves
|
||||||
|
if not interaction.is_expired():
|
||||||
|
splat = interaction.client.tree.bugsplat(interaction, error)
|
||||||
|
try:
|
||||||
|
if interaction.response.is_done():
|
||||||
|
await interaction.followup.send(embed=splat, ephemeral=True)
|
||||||
|
else:
|
||||||
|
await interaction.response.send_message(embed=splat, ephemeral=True)
|
||||||
|
except discord.HTTPException:
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
class MessageUI(LeoUI):
|
class MessageUI(LeoUI):
|
||||||
@@ -461,9 +472,19 @@ class LeoModal(Modal):
|
|||||||
raise error
|
raise error
|
||||||
except Exception:
|
except Exception:
|
||||||
logger.exception(
|
logger.exception(
|
||||||
f"Unhandled interaction exception occurred in {self!r}",
|
f"Unhandled interaction exception occurred in {self!r}. Interaction: {interaction.data}",
|
||||||
extra={'with_ctx': True, 'action': 'ModalError'}
|
extra={'with_ctx': True, 'action': 'ModalError'}
|
||||||
)
|
)
|
||||||
|
# Explicitly handle the bugsplat ourselves
|
||||||
|
if not interaction.is_expired():
|
||||||
|
splat = interaction.client.tree.bugsplat(interaction, error)
|
||||||
|
try:
|
||||||
|
if interaction.response.is_done():
|
||||||
|
await interaction.followup.send(embed=splat, ephemeral=True)
|
||||||
|
else:
|
||||||
|
await interaction.response.send_message(embed=splat, ephemeral=True)
|
||||||
|
except discord.HTTPException:
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
def error_handler_for(exc):
|
def error_handler_for(exc):
|
||||||
|
|||||||
Reference in New Issue
Block a user