Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 23 additions & 7 deletions bot.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,9 @@
# Load environment variables
load_dotenv()

# Configure logging
logging.basicConfig(
level=getattr(logging, os.getenv("LOG_LEVEL", "INFO")),
format="%(asctime)s - %(name)s - %(levelname)s - %(message)s",
handlers=[logging.FileHandler("bot.log"), logging.StreamHandler()],
)
from utils.logger import setup_logging

setup_logging()
logger = logging.getLogger(__name__)


Expand Down Expand Up @@ -65,7 +62,8 @@ def __init__(self, config: Config):

async def setup_hook(self) -> None:
"""Setup hook called before the bot starts."""
# Initialize CodeBuddy database
self.tree.on_app_command_completion = self.on_app_command_completion

try:
from utils.codebuddy_database import init_db

Expand Down Expand Up @@ -176,6 +174,18 @@ async def on_ready(self):
activity=discord.Game(name="?helpmenu /help | Made by YC45")
)

async def on_command_completion(self, ctx: commands.Context):
"""Handle prefix command completion."""
from utils.logger import log_command_usage
log_command_usage(ctx, command_type="PREFIX", success=True)

async def on_app_command_completion(
self, interaction: discord.Interaction, command: app_commands.Command
):
"""Handle slash command completion."""
from utils.logger import log_command_usage
log_command_usage(interaction, command_type="SLASH", success=True)

async def on_command_error(
self, ctx: commands.Context, error: commands.CommandError
):
Expand All @@ -184,6 +194,9 @@ async def on_command_error(
if isinstance(error, commands.CommandNotFound):
return

from utils.logger import log_command_usage
log_command_usage(ctx, command_type="PREFIX", success=False, error=error)

async def _safe_ctx_send(message: str) -> None:
"""Send a message without crashing on expired slash interactions.

Expand Down Expand Up @@ -235,6 +248,9 @@ async def on_app_command_error(
self, interaction: discord.Interaction, error: app_commands.AppCommandError
):
"""Handle slash command errors."""
from utils.logger import log_command_usage
log_command_usage(interaction, command_type="SLASH", success=False, error=error)

# Silence unknown slash/app commands.
# `app_commands` doesn't expose a stable CommandNotFound across versions, so be conservative.

Expand Down
61 changes: 61 additions & 0 deletions utils/logger.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import logging
import os
import discord
from discord.ext import commands

logger = logging.getLogger("EigenBot")

def setup_logging():
log_level_str = os.getenv("LOG_LEVEL", "INFO")
log_level = getattr(logging, log_level_str.upper(), logging.INFO)

os.makedirs("logs", exist_ok=True)
file_handler = logging.FileHandler(os.path.join("logs", "bot.log"), encoding="utf-8")
stream_handler = logging.StreamHandler()

formatter = logging.Formatter("%(asctime)s - %(name)s - %(levelname)s - %(message)s")
file_handler.setFormatter(formatter)
stream_handler.setFormatter(formatter)

root_logger = logging.getLogger()
root_logger.setLevel(log_level)
root_logger.handlers.clear()
root_logger.addHandler(file_handler)
root_logger.addHandler(stream_handler)

logger.info("Logging system configured successfully.")

def log_command_usage(ctx_or_interaction, command_type: str, success: bool, error: Exception = None):
"""Formats and logs command usage consistently."""
try:
if isinstance(ctx_or_interaction, commands.Context):
user_id = ctx_or_interaction.author.id
username = ctx_or_interaction.author.name
if ctx_or_interaction.command:
command_name = ctx_or_interaction.command.qualified_name
else:
command_name = "Unknown"
elif isinstance(ctx_or_interaction, discord.Interaction):
user_id = ctx_or_interaction.user.id
username = ctx_or_interaction.user.name
if ctx_or_interaction.command:
command_name = ctx_or_interaction.command.qualified_name
elif ctx_or_interaction.data:
command_name = ctx_or_interaction.data.get("name", "Unknown")
else:
command_name = "Unknown"
else:
return

status = "SUCCESS" if success else f"FAILED ({type(error).__name__}: {error})"
message = (
f"[{command_type}] User: {username} ({user_id}) | "
f"Command: {command_name} | Status: {status}"
)

if success:
logger.info(message)
else:
logger.error(message)
except Exception as log_err:
logger.error(f"Failed to write command log: {log_err}")
Loading