refactor(bot): bot utilities into separate modules

Moved logging, signal handling, and uptime calculation logic from bot.py into dedicated utils modules for better organization and reusability. Updated imports and usage in bot.py and utils/__init__.py accordingly.
This commit is contained in:
neoarz
2025-09-28 16:20:28 -04:00
parent 0a262c522e
commit 4948d2edf7
5 changed files with 96 additions and 73 deletions

View File

@@ -1,3 +1,9 @@
from .ascii_art import ascii, ascii_plain, gradient_text, gradient_text_selective
from .logging import LoggingFormatter, setup_logger
from .time import get_uptime
from .signal import setup_signal_handlers
__all__ = ['ascii', 'ascii_plain', 'gradient_text', 'gradient_text_selective']
__all__ = [
'ascii', 'ascii_plain', 'gradient_text', 'gradient_text_selective',
'LoggingFormatter', 'setup_logger', 'get_uptime', 'setup_signal_handlers'
]

54
utils/logging.py Normal file
View File

@@ -0,0 +1,54 @@
import logging
import os
class LoggingFormatter(logging.Formatter):
black = "\x1b[30m"
red = "\x1b[31m"
green = "\x1b[32m"
yellow = "\x1b[33m"
blue = "\x1b[34m"
gray = "\x1b[38m"
reset = "\x1b[0m"
bold = "\x1b[1m"
COLORS = {
logging.DEBUG: gray + bold,
logging.INFO: blue + bold,
logging.WARNING: yellow + bold,
logging.ERROR: red,
logging.CRITICAL: red + bold,
}
def format(self, record):
log_color = self.COLORS[record.levelno]
format = "(black){asctime}(reset) (levelcolor){levelname:<8}(reset) (green){name}(reset) {message}"
format = format.replace("(black)", self.black + self.bold)
format = format.replace("(reset)", self.reset)
format = format.replace("(levelcolor)", log_color)
format = format.replace("(green)", self.green + self.bold)
formatter = logging.Formatter(format, "%Y-%m-%d %H:%M:%S", style="{")
return formatter.format(record)
def setup_logger():
logger = logging.getLogger("discord_bot")
logger.setLevel(logging.INFO)
console_handler = logging.StreamHandler()
console_handler.setFormatter(LoggingFormatter())
log_file_path = os.getenv("LOG_FILE", "logs/discord.log")
log_dir = os.path.dirname(log_file_path)
if log_dir:
os.makedirs(log_dir, exist_ok=True)
file_handler = logging.FileHandler(filename=log_file_path, encoding="utf-8", mode="w")
file_handler_formatter = logging.Formatter(
"[{asctime}] [{levelname:<8}] {name}: {message}", "%Y-%m-%d %H:%M:%S", style="{"
)
file_handler.setFormatter(file_handler_formatter)
logger.addHandler(console_handler)
logger.addHandler(file_handler)
return logger

13
utils/signal.py Normal file
View File

@@ -0,0 +1,13 @@
import asyncio
import signal
def setup_signal_handlers(bot):
def signal_handler(signum, frame):
bot.logger.info("Shutdown requested. Closing bot...")
if bot.loop and not bot.loop.is_closed():
asyncio.create_task(bot.close())
bot.loop.call_soon_threadsafe(bot.loop.stop)
signal.signal(signal.SIGINT, signal_handler)
signal.signal(signal.SIGTERM, signal_handler)

18
utils/time.py Normal file
View File

@@ -0,0 +1,18 @@
import time
def get_uptime(start_time: float) -> str:
uptime_seconds = int(time.time() - start_time)
days = uptime_seconds // 86400
hours = (uptime_seconds % 86400) // 3600
minutes = (uptime_seconds % 3600) // 60
seconds = uptime_seconds % 60
if days > 0:
return f"{days}d {hours}h {minutes}m {seconds}s"
elif hours > 0:
return f"{hours}h {minutes}m {seconds}s"
elif minutes > 0:
return f"{minutes}m {seconds}s"
else:
return f"{seconds}s"