Skip to content

Commit

Permalink
Merge pull request #218 from SylteA/feature/app-commands/errors
Browse files Browse the repository at this point in the history
Add some basic error handling
  • Loading branch information
SylteA authored Jul 17, 2023
2 parents d6ecfa8 + 81bbe4d commit 50ae6a6
Show file tree
Hide file tree
Showing 3 changed files with 58 additions and 3 deletions.
10 changes: 10 additions & 0 deletions bot/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,14 @@ class Timathon(BaseModel):
participant_role_id: int


class Hastebin(BaseModel):
base_url: str


class ErrorHandling(BaseModel):
webhook_url: str


class Settings(BaseSettings):
aoc: AoC
bot: Bot
Expand All @@ -101,6 +109,8 @@ class Settings(BaseSettings):
reaction_roles: ReactionRoles
tags: Tags
timathon: Timathon
hastebin: Hastebin
errors: ErrorHandling

class Config:
env_file = ".env"
Expand Down
30 changes: 27 additions & 3 deletions bot/core.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
import datetime
import logging
import os
import traceback

import discord
from discord import app_commands
from discord.ext import commands, tasks

from bot.config import settings
from bot.services import http, paste
from utils.time import human_timedelta

log = logging.getLogger(__name__)
Expand All @@ -23,6 +25,8 @@ def __init__(self, prefixes: tuple[str, ...], extensions: tuple[str, ...], inten
self.start_time = datetime.datetime.utcnow()
self.initial_extensions = extensions

self.error_webhook: discord.Webhook | None = None

async def resolve_user(self, user_id: int) -> discord.User | None:
"""Resolve a user from their ID."""
user = self.get_user(user_id)
Expand All @@ -45,6 +49,8 @@ async def setup_hook(self) -> None:

self.tree.on_error = self.on_app_command_error

self.error_webhook = discord.Webhook.from_url(url=settings.errors.webhook_url, session=http.session)

async def when_online(self):
log.info("Waiting until bot is ready to load extensions and app commands.")
await self.wait_until_ready()
Expand Down Expand Up @@ -92,15 +98,33 @@ async def on_app_command_error(self, interaction: "InteractionType", error: app_
if interaction.command is None:
return log.error("Ignoring exception in command tree.", exc_info=error)

if interaction.command._has_any_error_handlers():
return

if isinstance(error, app_commands.CheckFailure):
log.info(f"{interaction.user} failed to use the command {interaction.command.qualified_name}")
return

await self.publish_error(interaction=interaction, error=error)
log.error("Ignoring unhandled exception", exc_info=error)

async def publish_error(self, interaction: "InteractionType", error: app_commands.AppCommandError) -> None:
"""Publishes the error to our error webhook."""
content = "\n".join(traceback.format_exception(type(error), error, error.__traceback__))
header = f"Ignored exception in command **{interaction.command.qualified_name}**"

def wrap(code: str) -> str:
code = code.replace("`", "\u200b`")
return f"```py\n{code}\n```"

if len(content) > 1024: # Keeping it short for readability.
document = await paste.create(content)
content = wrap(content[:1024]) + f"\n\n [Full traceback]({document.url})"
else:
content = wrap(content)

embed = discord.Embed(
title=header, description=content, color=discord.Color.red(), timestamp=discord.utils.utcnow()
)
await self.error_webhook.send(embed=embed)

@tasks.loop(hours=24)
async def presence(self):
await self.wait_until_ready()
Expand Down
21 changes: 21 additions & 0 deletions bot/services/paste.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
from pydantic import BaseModel

from bot.config import settings
from bot.services import http


class Document(BaseModel):
key: str

@property
def url(self) -> str:
return settings.hastebin.base_url + "/" + self.key


async def create(content: str) -> Document:
"""Creates a hastebin Document with the provided content."""
async with http.session.post(settings.hastebin.base_url + "/documents", data=content) as response:
response.raise_for_status()

data = await response.json()
return Document(**data)

0 comments on commit 50ae6a6

Please sign in to comment.