128 lines
No EOL
4.4 KiB
Python
128 lines
No EOL
4.4 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
Logging Configuration - Dual output to terminal and file for crash tracking
|
|
"""
|
|
|
|
import logging
|
|
import sys
|
|
import os
|
|
from datetime import datetime
|
|
|
|
def setup_dual_logging(log_level=logging.INFO):
|
|
"""
|
|
Configure logging to output to both terminal and file
|
|
|
|
Args:
|
|
log_level: Logging level (default: logging.INFO)
|
|
|
|
Returns:
|
|
logger: Configured logger instance
|
|
"""
|
|
|
|
# Create logger
|
|
logger = logging.getLogger('master_adapt_detect')
|
|
logger.setLevel(log_level)
|
|
|
|
# Prevent duplicate handlers if called multiple times
|
|
if logger.handlers:
|
|
return logger
|
|
|
|
# Create formatter
|
|
formatter = logging.Formatter(
|
|
'%(asctime)s - %(name)s - %(levelname)s - %(message)s',
|
|
datefmt='%Y-%m-%d %H:%M:%S'
|
|
)
|
|
|
|
# Console handler (terminal output)
|
|
console_handler = logging.StreamHandler(sys.stdout)
|
|
console_handler.setLevel(log_level)
|
|
console_handler.setFormatter(formatter)
|
|
logger.addHandler(console_handler)
|
|
|
|
# File handler (file output)
|
|
log_filename = f"master_adapt_detect_{datetime.now().strftime('%Y%m%d_%H%M%S')}.log"
|
|
file_handler = logging.FileHandler(log_filename, mode='w')
|
|
file_handler.setLevel(log_level)
|
|
file_handler.setFormatter(formatter)
|
|
logger.addHandler(file_handler)
|
|
|
|
# Log the setup
|
|
logger.info(f"Dual logging initialized - Console: {log_level}, File: {log_filename}")
|
|
|
|
return logger
|
|
|
|
def log_system_info(logger):
|
|
"""Log system information for debugging"""
|
|
import platform
|
|
import psutil
|
|
|
|
logger.info("="*60)
|
|
logger.info("SYSTEM INFORMATION")
|
|
logger.info("="*60)
|
|
logger.info(f"Platform: {platform.platform()}")
|
|
logger.info(f"Python version: {platform.python_version()}")
|
|
logger.info(f"CPU count: {psutil.cpu_count()}")
|
|
logger.info(f"Memory: {psutil.virtual_memory().total / (1024**3):.2f} GB total")
|
|
logger.info(f"Available memory: {psutil.virtual_memory().available / (1024**3):.2f} GB")
|
|
logger.info(f"Process ID: {os.getpid()}")
|
|
logger.info("="*60)
|
|
|
|
def log_exception(logger, exc_info=None):
|
|
"""Log exception with full traceback"""
|
|
if exc_info is None:
|
|
exc_info = sys.exc_info()
|
|
|
|
logger.error("EXCEPTION OCCURRED", exc_info=exc_info)
|
|
|
|
# Also log memory usage at time of crash
|
|
try:
|
|
import psutil
|
|
process = psutil.Process()
|
|
memory_info = process.memory_info()
|
|
system_memory = psutil.virtual_memory()
|
|
swap_memory = psutil.swap_memory()
|
|
|
|
logger.error(f"System memory at crash: {system_memory.percent:.1f}% used, "
|
|
f"{system_memory.available / (1024**3):.2f} GB available")
|
|
logger.error(f"Swap memory at crash: {swap_memory.percent:.1f}% used, "
|
|
f"{swap_memory.used / (1024**3):.2f} GB used")
|
|
logger.error(f"Process memory at crash: RSS={memory_info.rss / (1024**3):.2f} GB, "
|
|
f"VMS={memory_info.vms / (1024**3):.2f} GB")
|
|
logger.error(f"CPU usage at crash: {process.cpu_percent()}%")
|
|
except Exception as e:
|
|
logger.error(f"Could not get resource usage: {e}")
|
|
|
|
def log_memory_warning(logger, usage):
|
|
"""Log memory warning with details"""
|
|
logger.warning(f"MEMORY WARNING: {usage['memory_percent']:.1f}% memory used, "
|
|
f"{usage['memory_available_gb']:.1f} GB available")
|
|
if usage['swap_percent'] > 0:
|
|
logger.warning(f"SWAP WARNING: {usage['swap_percent']:.1f}% swap used, "
|
|
f"{usage['swap_used_gb']:.1f} GB used")
|
|
|
|
class DualLogger:
|
|
"""Wrapper class to provide print-like interface with dual logging"""
|
|
|
|
def __init__(self, logger):
|
|
self.logger = logger
|
|
|
|
def print(self, *args, **kwargs):
|
|
"""Print to both terminal and file"""
|
|
# Convert args to string like print() would
|
|
message = ' '.join(str(arg) for arg in args)
|
|
self.logger.info(message)
|
|
|
|
def error(self, *args, **kwargs):
|
|
"""Log error message"""
|
|
message = ' '.join(str(arg) for arg in args)
|
|
self.logger.error(message)
|
|
|
|
def warning(self, *args, **kwargs):
|
|
"""Log warning message"""
|
|
message = ' '.join(str(arg) for arg in args)
|
|
self.logger.warning(message)
|
|
|
|
def debug(self, *args, **kwargs):
|
|
"""Log debug message"""
|
|
message = ' '.join(str(arg) for arg in args)
|
|
self.logger.debug(message) |