Files
discord-fishbowl/src/utils/logging.py
root 5480219901 Fix comprehensive system issues and implement proper vector database backend selection
- Fix remaining datetime timezone errors across all database operations
- Implement dynamic vector database backend (Qdrant/ChromaDB) based on install.py configuration
- Add LLM timeout handling with immediate fallback responses for slow self-hosted models
- Use proper install.py configuration (2000 max tokens, 5min timeout, correct LLM endpoint)
- Fix PostgreSQL schema to use timezone-aware columns throughout
- Implement async LLM request handling with background processing
- Add configurable prompt limits and conversation history controls
- Start missing database services (PostgreSQL, Redis) automatically
- Fix environment variable mapping between install.py and application code
- Resolve all timezone-naive vs timezone-aware datetime conflicts

System now properly uses Qdrant vector database as specified in install.py instead of hardcoded ChromaDB.
Characters respond immediately with fallback messages during long LLM processing times.
All database timezone errors resolved with proper timestamptz columns.
2025-07-05 21:31:52 -07:00

128 lines
4.2 KiB
Python

import logging
from loguru import logger
from typing import Dict, Any
import sys
import traceback
from datetime import datetime, timezone
class InterceptHandler(logging.Handler):
"""Intercept standard logging and route to loguru"""
def emit(self, record):
try:
level = logger.level(record.levelname).name
except ValueError:
level = record.levelno
frame, depth = logging.currentframe(), 2
while frame.f_code.co_filename == logging.__file__:
frame = frame.f_back
depth += 1
logger.opt(depth=depth, exception=record.exc_info).log(
level, record.getMessage()
)
def setup_logging_interceptor():
"""Setup logging to intercept standard library logging"""
logging.basicConfig(handlers=[InterceptHandler()], level=0, force=True)
# Silence some noisy loggers
logging.getLogger("discord").setLevel(logging.WARNING)
logging.getLogger("discord.http").setLevel(logging.WARNING)
logging.getLogger("asyncio").setLevel(logging.WARNING)
def log_character_action(character_name: str, action: str, details: Dict[str, Any] = None):
"""Log character-specific actions"""
logger.info(f"Character {character_name}: {action}", extra={"details": details or {}})
def log_conversation_event(conversation_id: int, event: str, participants: list = None, details: Dict[str, Any] = None):
"""Log conversation events"""
logger.info(
f"Conversation {conversation_id}: {event}",
extra={
"participants": participants or [],
"details": details or {}
}
)
def log_llm_interaction(character_name: str, prompt_length: int, response_length: int, model: str, duration: float):
"""Log LLM API interactions"""
logger.info(
f"LLM interaction for {character_name}",
extra={
"prompt_length": prompt_length,
"response_length": response_length,
"model": model,
"duration": duration
}
)
def log_error_with_context(error: Exception, context: Dict[str, Any] = None):
"""Log errors with additional context"""
logger.error(
f"Error: {str(error)}",
extra={
"error_type": type(error).__name__,
"traceback": traceback.format_exc(),
"context": context or {}
}
)
def log_database_operation(operation: str, table: str, duration: float, success: bool = True):
"""Log database operations"""
level = "info" if success else "error"
logger.log(
level,
f"Database {operation} on {table}",
extra={
"duration": duration,
"success": success
}
)
def log_autonomous_decision(character_name: str, decision: str, reasoning: str, context: Dict[str, Any] = None):
"""Log autonomous character decisions"""
logger.info(
f"Character {character_name} decision: {decision}",
extra={
"reasoning": reasoning,
"context": context or {}
}
)
def log_memory_operation(character_name: str, operation: str, memory_type: str, importance: float = None):
"""Log memory operations"""
logger.info(
f"Memory {operation} for {character_name}",
extra={
"memory_type": memory_type,
"importance": importance
}
)
def log_relationship_change(character_a: str, character_b: str, old_relationship: str, new_relationship: str, reason: str):
"""Log relationship changes between characters"""
logger.info(
f"Relationship change: {character_a} <-> {character_b}",
extra={
"old_relationship": old_relationship,
"new_relationship": new_relationship,
"reason": reason
}
)
def create_performance_logger():
"""Create a performance-focused logger"""
performance_logger = logger.bind(category="performance")
return performance_logger
def log_system_health(component: str, status: str, metrics: Dict[str, Any] = None):
"""Log system health metrics"""
logger.info(
f"System health - {component}: {status}",
extra={
"metrics": metrics or {},
"timestamp": datetime.now(timezone.utc).isoformat()
}
)