From 68b409849457d5935b1791fb42c6057d1d92fcd5 Mon Sep 17 00:00:00 2001 From: Adam Piskorski Date: Mon, 19 May 2025 17:31:45 -0400 Subject: [PATCH 1/3] chore: Ignore vscode config --- discord/.gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/discord/.gitignore b/discord/.gitignore index 4d00e65..7cc6346 100644 --- a/discord/.gitignore +++ b/discord/.gitignore @@ -8,3 +8,4 @@ __pycache__ registered_log.txt schedule.json pretix_cache.json +.vscode/ \ No newline at end of file From f14ba6843f3ce6efa6dd820b657536b76444f42e Mon Sep 17 00:00:00 2001 From: Adam Piskorski Date: Mon, 19 May 2025 20:50:02 -0400 Subject: [PATCH 2/3] style: Auto import sorter is gonna sort --- discord/PyLadiesBot/bot.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/discord/PyLadiesBot/bot.py b/discord/PyLadiesBot/bot.py index b823cea..4c9cb8b 100644 --- a/discord/PyLadiesBot/bot.py +++ b/discord/PyLadiesBot/bot.py @@ -4,13 +4,12 @@ import sys from pathlib import Path -import discord -from discord.ext import commands -from dotenv import load_dotenv - import configuration +import discord from cogs.ping import Ping from cogs.pretix_donations import PretixDonations +from discord.ext import commands +from dotenv import load_dotenv from program_notifications.cog import ProgramNotificationsCog from registration.cog import RegistrationCog From d8f25c7048850c46a5c948347414267f046237a6 Mon Sep 17 00:00:00 2001 From: Adam Piskorski Date: Mon, 19 May 2025 20:50:27 -0400 Subject: [PATCH 3/3] feat: Add discord logger and one use of it in the ping cog --- discord/PyLadiesBot/cogs/ping.py | 4 +- discord/PyLadiesBot/config.toml | 1 + discord/PyLadiesBot/configuration.py | 4 +- discord/PyLadiesBot/helpers.py | 78 +++++++++++++++++++++++++ discord/PyLadiesBot/staging-config.toml | 1 + 5 files changed, 86 insertions(+), 2 deletions(-) create mode 100644 discord/PyLadiesBot/helpers.py diff --git a/discord/PyLadiesBot/cogs/ping.py b/discord/PyLadiesBot/cogs/ping.py index 7ddc64d..2b1848c 100644 --- a/discord/PyLadiesBot/cogs/ping.py +++ b/discord/PyLadiesBot/cogs/ping.py @@ -1,6 +1,7 @@ import logging from discord.ext import commands +from helpers import DiscordLogger _logger = logging.getLogger(f"bot.{__name__}") @@ -9,8 +10,9 @@ class Ping(commands.Cog): def __init__(self, bot: commands.Bot): self.bot: commands.Bot = bot _logger.info("Cog 'Ping' has been initialized") + self.discord_logger = DiscordLogger(__name__, self.bot) @commands.hybrid_command(name="ping", description="Ping the bot") async def ping_command(self, ctx: commands.Context) -> None: - _logger.debug("The 'ping' command has been triggered!") + await self.discord_logger.info("The 'ping' command has been triggered!") await ctx.send("Pong!") diff --git a/discord/PyLadiesBot/config.toml b/discord/PyLadiesBot/config.toml index a1dd794..223e251 100644 --- a/discord/PyLadiesBot/config.toml +++ b/discord/PyLadiesBot/config.toml @@ -42,6 +42,7 @@ DONATIONS_CHANNEL_ID = 1314028552223457471 [logging] LOG_LEVEL = "INFO" +channel_id = "TO SET" [program_notifications] # UTC offset in hours (e.g. 2 for CEST) diff --git a/discord/PyLadiesBot/configuration.py b/discord/PyLadiesBot/configuration.py index b05ae2f..b729ff7 100644 --- a/discord/PyLadiesBot/configuration.py +++ b/discord/PyLadiesBot/configuration.py @@ -1,9 +1,10 @@ import logging import sys -import tomllib from datetime import datetime, timedelta, timezone from pathlib import Path +import tomllib + _logger = logging.getLogger(f"bot.{__name__}") @@ -76,6 +77,7 @@ def __init__(self): # Logging self.LOG_LEVEL = config.get("logging", {}).get("LOG_LEVEL", "INFO") + self.log_channel = config["logging"]["channel_id"] except KeyError: _logger.exception( diff --git a/discord/PyLadiesBot/helpers.py b/discord/PyLadiesBot/helpers.py new file mode 100644 index 0000000..622ad00 --- /dev/null +++ b/discord/PyLadiesBot/helpers.py @@ -0,0 +1,78 @@ +import logging +import textwrap + +from configuration import Config +from discord import Message +from discord.abc import Messageable +from discord.ext.commands import Bot + +config = Config() + + +async def safe_send_message(target: Messageable, text: str) -> list[Message]: + """Safely send a message to the given messageable target. + The utility of this is function, is that the message will be split into multiple parts + if its too long. + """ + messages = [] + for part in textwrap.wrap( + text, + width=2000, + expand_tabs=False, + replace_whitespace=False, + drop_whitespace=False, + ): + message = await target.send(part) + messages.append(message) + return messages + + +class DiscordLogger: + """Wrapper for the configured project logger, that also sends the same logs to discord. + + Use any of the logging level methods, just like in the standard library on the + instantiated object. + + Automatically prefixes `bot.` to the name provided for the logger. + + Requires a bot object to be instantiated and passed into it. + + For example: + ```python + discord_logger = DiscordLogger(__name__, self.bot) + discord_logger.info("The 'ping' command has been triggered!") + discord_logger.error("A problem has occurred!") + ``` + """ + + def __init__(self, name: str, bot: Bot): + self.name = f"bot.{name}" + self.bot = bot + self.logger = logging.getLogger(self.name) + + def __getattr__(self, method_name: str): + logging_types = { + "debug", + "info", + "warning", + "warn", + "error", + "exception", + "critical", + "fatal", + } + if method_name not in logging_types: + raise AttributeError(f"Logging type must be one of {logging_types}") + + def _log(message: str): + + async def inner(): + logging_method = getattr(self.logger, method_name) + logging_method(message) + channel = self.bot.get_channel(config.log_channel) + prefix = f"{self.name} - {method_name.upper()} - " + await safe_send_message(channel, f"{prefix}{message}") + + return inner() + + return _log diff --git a/discord/PyLadiesBot/staging-config.toml b/discord/PyLadiesBot/staging-config.toml index 1d0cc86..8caab1f 100644 --- a/discord/PyLadiesBot/staging-config.toml +++ b/discord/PyLadiesBot/staging-config.toml @@ -38,6 +38,7 @@ PRETIX_CACHE_FILE = "pretix_cache.json" [logging] LOG_LEVEL = "INFO" +channel_id = "TO SET" [program_notifications] # UTC offset in hours (e.g. 2 for CEST)