#!/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)