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:
@@ -9,6 +9,9 @@ import time
|
||||
from utils.autonomous_engine import autonomous_engine
|
||||
from server_manager import server_manager
|
||||
import globals
|
||||
from utils.logger import get_logger
|
||||
|
||||
logger = get_logger('autonomous')
|
||||
|
||||
# Rate limiting: Track last action time per server to prevent rapid-fire
|
||||
_last_action_execution = {} # guild_id -> timestamp
|
||||
@@ -25,7 +28,7 @@ async def autonomous_tick_v2(guild_id: int):
|
||||
if guild_id in _last_action_execution:
|
||||
time_since_last = now - _last_action_execution[guild_id]
|
||||
if time_since_last < _MIN_ACTION_INTERVAL:
|
||||
print(f"⏱️ [V2] Rate limit: Only {time_since_last:.0f}s since last action (need {_MIN_ACTION_INTERVAL}s)")
|
||||
logger.debug(f"[V2] Rate limit: Only {time_since_last:.0f}s since last action (need {_MIN_ACTION_INTERVAL}s)")
|
||||
return
|
||||
|
||||
# Ask the engine if Miku should act (with optional debug logging)
|
||||
@@ -35,7 +38,7 @@ async def autonomous_tick_v2(guild_id: int):
|
||||
# Engine decided not to act
|
||||
return
|
||||
|
||||
print(f"🤖 [V2] Autonomous engine decided to: {action_type} for server {guild_id}")
|
||||
logger.info(f"[V2] Autonomous engine decided to: {action_type} for server {guild_id}")
|
||||
|
||||
# Execute the action using legacy functions
|
||||
from utils.autonomous_v1_legacy import (
|
||||
@@ -58,12 +61,12 @@ async def autonomous_tick_v2(guild_id: int):
|
||||
elif action_type == "change_profile_picture":
|
||||
# Get current mood for this server
|
||||
mood, _ = server_manager.get_server_mood(guild_id)
|
||||
print(f"🎨 [V2] Changing profile picture (mood: {mood})")
|
||||
logger.info(f"[V2] Changing profile picture (mood: {mood})")
|
||||
result = await profile_picture_manager.change_profile_picture(mood=mood, debug=True)
|
||||
if result["success"]:
|
||||
print(f"✅ Profile picture changed successfully!")
|
||||
logger.info(f"Profile picture changed successfully!")
|
||||
else:
|
||||
print(f"⚠️ Profile picture change failed: {result.get('error')}")
|
||||
logger.warning(f"Profile picture change failed: {result.get('error')}")
|
||||
|
||||
# Record that action was taken
|
||||
autonomous_engine.record_action(guild_id)
|
||||
@@ -84,10 +87,10 @@ async def autonomous_tick_v2(guild_id: int):
|
||||
if channel:
|
||||
await maybe_trigger_argument(channel, globals.client, "Triggered after an autonomous action")
|
||||
except Exception as bipolar_err:
|
||||
print(f"⚠️ Bipolar check error: {bipolar_err}")
|
||||
logger.warning(f"Bipolar check error: {bipolar_err}")
|
||||
|
||||
except Exception as e:
|
||||
print(f"⚠️ Error executing autonomous action: {e}")
|
||||
logger.error(f"Error executing autonomous action: {e}")
|
||||
|
||||
|
||||
async def autonomous_reaction_tick_v2(guild_id: int):
|
||||
@@ -101,7 +104,7 @@ async def autonomous_reaction_tick_v2(guild_id: int):
|
||||
if not should_react:
|
||||
return
|
||||
|
||||
print(f"🤖 [V2] Scheduled reaction check triggered for server {guild_id}")
|
||||
logger.debug(f"[V2] Scheduled reaction check triggered for server {guild_id}")
|
||||
|
||||
try:
|
||||
from utils.autonomous_v1_legacy import miku_autonomous_reaction_for_server
|
||||
@@ -112,7 +115,7 @@ async def autonomous_reaction_tick_v2(guild_id: int):
|
||||
autonomous_engine.record_action(guild_id)
|
||||
|
||||
except Exception as e:
|
||||
print(f"⚠️ Error executing scheduled reaction: {e}")
|
||||
logger.error(f"Error executing scheduled reaction: {e}")
|
||||
|
||||
|
||||
def on_message_event(message):
|
||||
@@ -160,7 +163,7 @@ async def _check_and_react(guild_id: int, message):
|
||||
should_react = autonomous_engine.should_react_to_message(guild_id, message_age)
|
||||
|
||||
if should_react:
|
||||
print(f"🎯 [V2] Real-time reaction triggered for message from {message.author.display_name}")
|
||||
logger.info(f"[V2] Real-time reaction triggered for message from {message.author.display_name}")
|
||||
from utils.autonomous_v1_legacy import miku_autonomous_reaction_for_server
|
||||
await miku_autonomous_reaction_for_server(guild_id, force_message=message)
|
||||
|
||||
@@ -186,7 +189,7 @@ async def _check_and_act(guild_id: int):
|
||||
action_type = autonomous_engine.should_take_action(guild_id, triggered_by_message=True)
|
||||
|
||||
if action_type:
|
||||
print(f"🎯 [V2] Message triggered autonomous action: {action_type}")
|
||||
logger.info(f"[V2] Message triggered autonomous action: {action_type}")
|
||||
|
||||
# Execute the action directly (don't call autonomous_tick_v2 which would check again)
|
||||
from utils.autonomous_v1_legacy import (
|
||||
@@ -209,12 +212,12 @@ async def _check_and_act(guild_id: int):
|
||||
elif action_type == "change_profile_picture":
|
||||
# Get current mood for this server
|
||||
mood, _ = server_manager.get_server_mood(guild_id)
|
||||
print(f"🎨 [V2] Changing profile picture (mood: {mood})")
|
||||
logger.info(f"[V2] Changing profile picture (mood: {mood})")
|
||||
result = await profile_picture_manager.change_profile_picture(mood=mood, debug=True)
|
||||
if result["success"]:
|
||||
print(f"✅ Profile picture changed successfully!")
|
||||
logger.info(f"Profile picture changed successfully!")
|
||||
else:
|
||||
print(f"⚠️ Profile picture change failed: {result.get('error')}")
|
||||
logger.warning(f"Profile picture change failed: {result.get('error')}")
|
||||
|
||||
# Record that action was taken
|
||||
autonomous_engine.record_action(guild_id)
|
||||
@@ -232,10 +235,10 @@ async def _check_and_act(guild_id: int):
|
||||
if channel:
|
||||
await maybe_trigger_argument(channel, globals.client, "Triggered after message-based action")
|
||||
except Exception as bipolar_err:
|
||||
print(f"⚠️ Bipolar check error: {bipolar_err}")
|
||||
logger.warning(f"Bipolar check error: {bipolar_err}")
|
||||
|
||||
except Exception as e:
|
||||
print(f"⚠️ Error executing message-triggered action: {e}")
|
||||
logger.error(f"Error executing message-triggered action: {e}")
|
||||
|
||||
|
||||
def on_presence_update(member, before, after):
|
||||
@@ -256,7 +259,7 @@ def on_presence_update(member, before, after):
|
||||
# Track status changes
|
||||
if before.status != after.status:
|
||||
autonomous_engine.track_user_event(guild_id, "status_changed")
|
||||
print(f"👤 [V2] {member.display_name} status changed: {before.status} → {after.status}")
|
||||
logger.debug(f"[V2] {member.display_name} status changed: {before.status} → {after.status}")
|
||||
|
||||
# Track activity changes
|
||||
if before.activities != after.activities:
|
||||
@@ -272,7 +275,7 @@ def on_presence_update(member, before, after):
|
||||
"activity_started",
|
||||
{"activity_name": activity_name}
|
||||
)
|
||||
print(f"🎮 [V2] {member.display_name} started activity: {activity_name}")
|
||||
logger.debug(f"[V2] {member.display_name} started activity: {activity_name}")
|
||||
|
||||
|
||||
def on_member_join(member):
|
||||
@@ -310,17 +313,17 @@ async def periodic_decay_task():
|
||||
try:
|
||||
autonomous_engine.decay_events(guild_id)
|
||||
except Exception as e:
|
||||
print(f"⚠️ Error decaying events for guild {guild_id}: {e}")
|
||||
logger.warning(f"Error decaying events for guild {guild_id}: {e}")
|
||||
|
||||
# Save context to disk periodically
|
||||
try:
|
||||
autonomous_engine.save_context()
|
||||
except Exception as e:
|
||||
print(f"⚠️ Error saving autonomous context: {e}")
|
||||
logger.error(f"Error saving autonomous context: {e}")
|
||||
|
||||
uptime_hours = (time.time() - task_start_time) / 3600
|
||||
print(f"🧹 [V2] Decay task completed (iteration #{iteration_count}, uptime: {uptime_hours:.1f}h)")
|
||||
print(f" └─ Processed {len(guild_ids)} servers")
|
||||
logger.debug(f"[V2] Decay task completed (iteration #{iteration_count}, uptime: {uptime_hours:.1f}h)")
|
||||
logger.debug(f" └─ Processed {len(guild_ids)} servers")
|
||||
|
||||
|
||||
def initialize_v2_system(client):
|
||||
@@ -328,7 +331,7 @@ def initialize_v2_system(client):
|
||||
Initialize the V2 autonomous system.
|
||||
Call this from bot.py on startup.
|
||||
"""
|
||||
print("🚀 Initializing Autonomous V2 System...")
|
||||
logger.debug("Initializing Autonomous V2 System...")
|
||||
|
||||
# Initialize mood states for all servers
|
||||
for guild_id, server_config in server_manager.servers.items():
|
||||
@@ -337,7 +340,7 @@ def initialize_v2_system(client):
|
||||
# Start decay task
|
||||
client.loop.create_task(periodic_decay_task())
|
||||
|
||||
print("✅ Autonomous V2 System initialized")
|
||||
logger.info("Autonomous V2 System initialized")
|
||||
|
||||
|
||||
# ========== Legacy Function Wrappers ==========
|
||||
|
||||
Reference in New Issue
Block a user