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:
@@ -11,6 +11,9 @@ import discord
|
||||
import globals
|
||||
from utils.llm import query_llama
|
||||
from utils.dm_logger import dm_logger
|
||||
from utils.logger import get_logger
|
||||
|
||||
logger = get_logger('dm')
|
||||
|
||||
# Directories
|
||||
REPORTS_DIR = "memory/dm_reports"
|
||||
@@ -26,7 +29,7 @@ class DMInteractionAnalyzer:
|
||||
"""
|
||||
self.owner_user_id = owner_user_id
|
||||
os.makedirs(REPORTS_DIR, exist_ok=True)
|
||||
print(f"📊 DM Interaction Analyzer initialized for owner: {owner_user_id}")
|
||||
logger.info(f"DM Interaction Analyzer initialized for owner: {owner_user_id}")
|
||||
|
||||
def _load_reported_today(self) -> Dict[str, str]:
|
||||
"""Load the list of users reported today with their dates"""
|
||||
@@ -35,7 +38,7 @@ class DMInteractionAnalyzer:
|
||||
with open(REPORTED_TODAY_FILE, 'r', encoding='utf-8') as f:
|
||||
return json.load(f)
|
||||
except Exception as e:
|
||||
print(f"⚠️ Failed to load reported_today.json: {e}")
|
||||
logger.error(f"Failed to load reported_today.json: {e}")
|
||||
return {}
|
||||
return {}
|
||||
|
||||
@@ -45,7 +48,7 @@ class DMInteractionAnalyzer:
|
||||
with open(REPORTED_TODAY_FILE, 'w', encoding='utf-8') as f:
|
||||
json.dump(reported, f, indent=2)
|
||||
except Exception as e:
|
||||
print(f"⚠️ Failed to save reported_today.json: {e}")
|
||||
logger.error(f"Failed to save reported_today.json: {e}")
|
||||
|
||||
def _clean_old_reports(self, reported: Dict[str, str]) -> Dict[str, str]:
|
||||
"""Remove entries from reported_today that are older than 24 hours"""
|
||||
@@ -58,7 +61,7 @@ class DMInteractionAnalyzer:
|
||||
if now - report_date < timedelta(hours=24):
|
||||
cleaned[user_id] = date_str
|
||||
except Exception as e:
|
||||
print(f"⚠️ Failed to parse date for user {user_id}: {e}")
|
||||
logger.error(f"Failed to parse date for user {user_id}: {e}")
|
||||
|
||||
return cleaned
|
||||
|
||||
@@ -91,7 +94,7 @@ class DMInteractionAnalyzer:
|
||||
if msg_time >= cutoff_time:
|
||||
recent_messages.append(msg)
|
||||
except Exception as e:
|
||||
print(f"⚠️ Failed to parse message timestamp: {e}")
|
||||
logger.error(f"Failed to parse message timestamp: {e}")
|
||||
|
||||
return recent_messages
|
||||
|
||||
@@ -126,14 +129,14 @@ class DMInteractionAnalyzer:
|
||||
recent_messages = self._get_recent_messages(user_id, hours=24)
|
||||
|
||||
if not recent_messages:
|
||||
print(f"📊 No recent messages from user {username} ({user_id})")
|
||||
logger.debug(f"No recent messages from user {username} ({user_id})")
|
||||
return None
|
||||
|
||||
# Count user messages only (not bot responses)
|
||||
user_messages = [msg for msg in recent_messages if not msg.get("is_bot_message", False)]
|
||||
|
||||
if len(user_messages) < 3: # Minimum threshold for analysis
|
||||
print(f"📊 Not enough messages from user {username} ({user_id}) for analysis")
|
||||
logger.info(f"Not enough messages from user {username} ({user_id}) for analysis")
|
||||
return None
|
||||
|
||||
# Format messages for analysis
|
||||
@@ -174,7 +177,7 @@ Respond ONLY with the JSON object, no other text."""
|
||||
response_type="dm_analysis"
|
||||
)
|
||||
|
||||
print(f"📊 Raw LLM response for {username}:\n{response}\n")
|
||||
logger.debug(f"Raw LLM response for {username}:\n{response}\n")
|
||||
|
||||
# Parse JSON response
|
||||
# Remove markdown code blocks if present
|
||||
@@ -192,7 +195,7 @@ Respond ONLY with the JSON object, no other text."""
|
||||
if start_idx != -1 and end_idx != -1:
|
||||
cleaned_response = cleaned_response[start_idx:end_idx+1]
|
||||
|
||||
print(f"📊 Cleaned JSON for {username}:\n{cleaned_response}\n")
|
||||
logger.debug(f"Cleaned JSON for {username}:\n{cleaned_response}\n")
|
||||
|
||||
analysis = json.loads(cleaned_response)
|
||||
|
||||
@@ -205,11 +208,11 @@ Respond ONLY with the JSON object, no other text."""
|
||||
return analysis
|
||||
|
||||
except json.JSONDecodeError as e:
|
||||
print(f"⚠️ JSON parse error for user {username}: {e}")
|
||||
print(f"⚠️ Failed response: {response}")
|
||||
logger.error(f"JSON parse error for user {username}: {e}")
|
||||
logger.error(f"Failed response: {response}")
|
||||
return None
|
||||
except Exception as e:
|
||||
print(f"⚠️ Failed to analyze interaction for user {username}: {e}")
|
||||
logger.error(f"Failed to analyze interaction for user {username}: {e}")
|
||||
return None
|
||||
|
||||
def _save_report(self, user_id: int, analysis: Dict) -> str:
|
||||
@@ -221,10 +224,10 @@ Respond ONLY with the JSON object, no other text."""
|
||||
try:
|
||||
with open(filepath, 'w', encoding='utf-8') as f:
|
||||
json.dump(analysis, f, indent=2, ensure_ascii=False)
|
||||
print(f"💾 Saved report: {filepath}")
|
||||
logger.info(f"Saved report: {filepath}")
|
||||
return filepath
|
||||
except Exception as e:
|
||||
print(f"⚠️ Failed to save report: {e}")
|
||||
logger.error(f"Failed to save report: {e}")
|
||||
return ""
|
||||
|
||||
async def _send_report_to_owner(self, analysis: Dict):
|
||||
@@ -232,7 +235,7 @@ Respond ONLY with the JSON object, no other text."""
|
||||
try:
|
||||
# Ensure we're using the Discord client's event loop
|
||||
if not globals.client or not globals.client.is_ready():
|
||||
print(f"⚠️ Discord client not ready, cannot send report")
|
||||
logger.warning(f"Discord client not ready, cannot send report")
|
||||
return
|
||||
|
||||
owner = await globals.client.fetch_user(self.owner_user_id)
|
||||
@@ -294,10 +297,10 @@ Respond ONLY with the JSON object, no other text."""
|
||||
)
|
||||
|
||||
await owner.send(embed=embed)
|
||||
print(f"📤 Report sent to owner for user {username}")
|
||||
logger.info(f"Report sent to owner for user {username}")
|
||||
|
||||
except Exception as e:
|
||||
print(f"⚠️ Failed to send report to owner: {e}")
|
||||
logger.error(f"Failed to send report to owner: {e}")
|
||||
|
||||
async def analyze_and_report(self, user_id: int) -> bool:
|
||||
"""
|
||||
@@ -306,12 +309,11 @@ Respond ONLY with the JSON object, no other text."""
|
||||
Returns:
|
||||
True if analysis was performed and reported, False otherwise
|
||||
"""
|
||||
|
||||
# Check if already reported today
|
||||
if self.has_been_reported_today(user_id):
|
||||
print(f"📊 User {user_id} already reported today, skipping")
|
||||
return False
|
||||
|
||||
# Analyze interaction
|
||||
logger.debug(f"User {user_id} already reported today, skipping")
|
||||
return False # Analyze interaction
|
||||
analysis = await self.analyze_user_interaction(user_id)
|
||||
|
||||
if not analysis:
|
||||
@@ -331,13 +333,13 @@ Respond ONLY with the JSON object, no other text."""
|
||||
|
||||
async def run_daily_analysis(self):
|
||||
"""Run analysis on all DM users and report significant interactions"""
|
||||
print("📊 Starting daily DM interaction analysis...")
|
||||
logger.info("Starting daily DM interaction analysis...")
|
||||
|
||||
# Get all DM users
|
||||
all_users = dm_logger.get_all_dm_users()
|
||||
|
||||
if not all_users:
|
||||
print("📊 No DM users to analyze")
|
||||
logger.info("No DM users to analyze")
|
||||
return
|
||||
|
||||
reported_count = 0
|
||||
@@ -363,9 +365,9 @@ Respond ONLY with the JSON object, no other text."""
|
||||
analyzed_count += 1
|
||||
|
||||
except Exception as e:
|
||||
print(f"⚠️ Failed to process user {user_summary.get('username', 'Unknown')}: {e}")
|
||||
logger.error(f"Failed to process user {user_summary.get('username', 'Unknown')}: {e}")
|
||||
|
||||
print(f"📊 Daily analysis complete: Analyzed {analyzed_count} users, reported {reported_count}")
|
||||
logger.info(f"Daily analysis complete: Analyzed {analyzed_count} users, reported {reported_count}")
|
||||
|
||||
|
||||
# Global instance (will be initialized with owner ID)
|
||||
|
||||
Reference in New Issue
Block a user