feat: Implement comprehensive non-hierarchical logging system
- Created new logging infrastructure with per-component filtering - Added 6 log levels: DEBUG, INFO, API, WARNING, ERROR, CRITICAL - Implemented non-hierarchical level control (any combination can be enabled) - Migrated 917 print() statements across 31 files to structured logging - Created web UI (system.html) for runtime configuration with dark theme - Added global level controls to enable/disable levels across all components - Added timestamp format control (off/time/date/datetime options) - Implemented log rotation (10MB per file, 5 backups) - Added API endpoints for dynamic log configuration - Configured HTTP request logging with filtering via api.requests component - Intercepted APScheduler logs with proper formatting - Fixed persistence paths to use /app/memory for Docker volume compatibility - Fixed checkbox display bug in web UI (enabled_levels now properly shown) - Changed System Settings button to open in same tab instead of new window Components: bot, api, api.requests, autonomous, persona, vision, llm, conversation, mood, dm, scheduled, gpu, media, server, commands, sentiment, core, apscheduler All settings persist across container restarts via JSON config.
This commit is contained in:
@@ -7,6 +7,9 @@ import asyncio
|
||||
from discord.ext import tasks
|
||||
import globals
|
||||
import datetime
|
||||
from utils.logger import get_logger
|
||||
|
||||
logger = get_logger('mood')
|
||||
|
||||
MOOD_EMOJIS = {
|
||||
"asleep": "💤",
|
||||
@@ -47,7 +50,7 @@ def load_mood_description(mood_name: str) -> str:
|
||||
with open(path, "r", encoding="utf-8") as f:
|
||||
return f.read().strip()
|
||||
except FileNotFoundError:
|
||||
print(f"⚠️ Mood file '{mood_name}' not found. Falling back to default.")
|
||||
logger.warning(f"Mood file '{mood_name}' not found. Falling back to default.")
|
||||
# Return a default mood description instead of recursive call
|
||||
return "I'm feeling neutral and balanced today."
|
||||
|
||||
@@ -120,17 +123,17 @@ def detect_mood_shift(response_text, server_context=None):
|
||||
# For server context, check against server's current mood
|
||||
current_mood = server_context.get('current_mood_name', 'neutral')
|
||||
if current_mood != "sleepy":
|
||||
print(f"❎ Mood 'asleep' skipped - server mood isn't 'sleepy', it's '{current_mood}'")
|
||||
logger.debug(f"Mood 'asleep' skipped - server mood isn't 'sleepy', it's '{current_mood}'")
|
||||
continue
|
||||
else:
|
||||
# For DM context, check against DM mood
|
||||
if globals.DM_MOOD != "sleepy":
|
||||
print(f"❎ Mood 'asleep' skipped - DM mood isn't 'sleepy', it's '{globals.DM_MOOD}'")
|
||||
logger.debug(f"Mood 'asleep' skipped - DM mood isn't 'sleepy', it's '{globals.DM_MOOD}'")
|
||||
continue
|
||||
|
||||
for phrase in phrases:
|
||||
if phrase.lower() in response_text.lower():
|
||||
print(f"*️⃣ Mood keyword triggered: {phrase}")
|
||||
logger.info(f"Mood keyword triggered: {phrase}")
|
||||
return mood
|
||||
return None
|
||||
|
||||
@@ -155,13 +158,13 @@ async def rotate_dm_mood():
|
||||
globals.DM_MOOD = new_mood
|
||||
globals.DM_MOOD_DESCRIPTION = load_mood_description(new_mood)
|
||||
|
||||
print(f"🔄 DM mood rotated from {old_mood} to {new_mood}")
|
||||
logger.info(f"DM mood rotated from {old_mood} to {new_mood}")
|
||||
|
||||
# Note: We don't update server nicknames here because servers have their own independent moods.
|
||||
# DM mood only affects direct messages to users.
|
||||
|
||||
except Exception as e:
|
||||
print(f"❌ Exception in rotate_dm_mood: {e}")
|
||||
logger.error(f"Exception in rotate_dm_mood: {e}")
|
||||
|
||||
async def update_all_server_nicknames():
|
||||
"""
|
||||
@@ -171,8 +174,8 @@ async def update_all_server_nicknames():
|
||||
This function incorrectly used DM mood to update all server nicknames,
|
||||
breaking the independent per-server mood system.
|
||||
"""
|
||||
print("⚠️ WARNING: update_all_server_nicknames() is deprecated and should not be called!")
|
||||
print("⚠️ Use update_server_nickname(guild_id) for per-server nickname updates instead.")
|
||||
logger.warning("WARNING: update_all_server_nicknames() is deprecated and should not be called!")
|
||||
logger.warning("Use update_server_nickname(guild_id) for per-server nickname updates instead.")
|
||||
# Do nothing - this function should not modify nicknames
|
||||
|
||||
async def nickname_mood_emoji(guild_id: int):
|
||||
@@ -182,11 +185,11 @@ async def nickname_mood_emoji(guild_id: int):
|
||||
async def update_server_nickname(guild_id: int):
|
||||
"""Update nickname for a specific server based on its mood"""
|
||||
try:
|
||||
print(f"🎭 Starting nickname update for server {guild_id}")
|
||||
logger.debug(f"Starting nickname update for server {guild_id}")
|
||||
|
||||
# Check if bot is ready
|
||||
if not globals.client.is_ready():
|
||||
print(f"⚠️ Bot not ready yet, deferring nickname update for server {guild_id}")
|
||||
logger.warning(f"Bot not ready yet, deferring nickname update for server {guild_id}")
|
||||
return
|
||||
|
||||
# Check if evil mode is active
|
||||
@@ -196,7 +199,7 @@ async def update_server_nickname(guild_id: int):
|
||||
from server_manager import server_manager
|
||||
server_config = server_manager.get_server_config(guild_id)
|
||||
if not server_config:
|
||||
print(f"⚠️ No server config found for guild {guild_id}")
|
||||
logger.warning(f"No server config found for guild {guild_id}")
|
||||
return
|
||||
|
||||
if evil_mode:
|
||||
@@ -209,29 +212,29 @@ async def update_server_nickname(guild_id: int):
|
||||
emoji = MOOD_EMOJIS.get(mood, "")
|
||||
base_name = "Hatsune Miku"
|
||||
|
||||
print(f"🔍 Server {guild_id} mood is: {mood} (evil_mode={evil_mode})")
|
||||
print(f"🔍 Using emoji: {emoji}")
|
||||
logger.debug(f"Server {guild_id} mood is: {mood} (evil_mode={evil_mode})")
|
||||
logger.debug(f"Using emoji: {emoji}")
|
||||
|
||||
nickname = f"{base_name}{emoji}"
|
||||
print(f"🔍 New nickname will be: {nickname}")
|
||||
logger.debug(f"New nickname will be: {nickname}")
|
||||
|
||||
guild = globals.client.get_guild(guild_id)
|
||||
if guild:
|
||||
print(f"🔍 Found guild: {guild.name}")
|
||||
logger.debug(f"Found guild: {guild.name}")
|
||||
me = guild.get_member(globals.BOT_USER.id)
|
||||
if me is not None:
|
||||
print(f"🔍 Found bot member: {me.display_name}")
|
||||
logger.debug(f"Found bot member: {me.display_name}")
|
||||
try:
|
||||
await me.edit(nick=nickname)
|
||||
print(f"💱 Changed nickname to {nickname} in server {guild.name}")
|
||||
logger.info(f"Changed nickname to {nickname} in server {guild.name}")
|
||||
except Exception as e:
|
||||
print(f"⚠️ Failed to update nickname in server {guild.name}: {e}")
|
||||
logger.warning(f"Failed to update nickname in server {guild.name}: {e}")
|
||||
else:
|
||||
print(f"⚠️ Could not find bot member in server {guild.name}")
|
||||
logger.warning(f"Could not find bot member in server {guild.name}")
|
||||
else:
|
||||
print(f"⚠️ Could not find guild {guild_id}")
|
||||
logger.warning(f"Could not find guild {guild_id}")
|
||||
except Exception as e:
|
||||
print(f"⚠️ Error updating server nickname for guild {guild_id}: {e}")
|
||||
logger.error(f"Error updating server nickname for guild {guild_id}: {e}")
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
|
||||
@@ -268,7 +271,7 @@ async def rotate_server_mood(guild_id: int):
|
||||
|
||||
# Block transition to asleep unless coming from sleepy
|
||||
if new_mood_name == "asleep" and old_mood_name != "sleepy":
|
||||
print(f"❌ Cannot rotate to asleep from {old_mood_name}, must be sleepy first")
|
||||
logger.warning(f"Cannot rotate to asleep from {old_mood_name}, must be sleepy first")
|
||||
# Try to get a different mood
|
||||
attempts = 0
|
||||
while (new_mood_name == "asleep" or new_mood_name == old_mood_name) and attempts < 5:
|
||||
@@ -282,7 +285,7 @@ async def rotate_server_mood(guild_id: int):
|
||||
from utils.autonomous import on_mood_change
|
||||
on_mood_change(guild_id, new_mood_name)
|
||||
except Exception as mood_notify_error:
|
||||
print(f"⚠️ Failed to notify autonomous engine of mood change: {mood_notify_error}")
|
||||
logger.error(f"Failed to notify autonomous engine of mood change: {mood_notify_error}")
|
||||
|
||||
# If transitioning to asleep, set up auto-wake
|
||||
if new_mood_name == "asleep":
|
||||
@@ -298,22 +301,22 @@ async def rotate_server_mood(guild_id: int):
|
||||
from utils.autonomous import on_mood_change
|
||||
on_mood_change(guild_id, "neutral")
|
||||
except Exception as mood_notify_error:
|
||||
print(f"⚠️ Failed to notify autonomous engine of wake-up mood change: {mood_notify_error}")
|
||||
logger.error(f"Failed to notify autonomous engine of wake-up mood change: {mood_notify_error}")
|
||||
|
||||
await update_server_nickname(guild_id)
|
||||
print(f"🌅 Server {guild_id} woke up from auto-sleep (mood rotation)")
|
||||
logger.info(f"Server {guild_id} woke up from auto-sleep (mood rotation)")
|
||||
|
||||
globals.client.loop.create_task(delayed_wakeup())
|
||||
print(f"⏰ Scheduled auto-wake for server {guild_id} in 1 hour")
|
||||
logger.info(f"Scheduled auto-wake for server {guild_id} in 1 hour")
|
||||
|
||||
# Update nickname for this specific server
|
||||
await update_server_nickname(guild_id)
|
||||
|
||||
print(f"🔄 Rotated mood for server {guild_id} from {old_mood_name} to {new_mood_name}")
|
||||
logger.info(f"Rotated mood for server {guild_id} from {old_mood_name} to {new_mood_name}")
|
||||
except Exception as e:
|
||||
print(f"❌ Exception in rotate_server_mood for server {guild_id}: {e}")
|
||||
logger.error(f"Exception in rotate_server_mood for server {guild_id}: {e}")
|
||||
|
||||
async def clear_angry_mood_after_delay():
|
||||
"""Clear angry mood after delay (legacy function - now handled per-server)"""
|
||||
print("⚠️ clear_angry_mood_after_delay called - this function is deprecated")
|
||||
logger.warning("clear_angry_mood_after_delay called - this function is deprecated")
|
||||
pass
|
||||
|
||||
Reference in New Issue
Block a user