logging
This commit is contained in:
@ -38,21 +38,15 @@ class SafeFormatter(logging.Formatter):
|
||||
|
||||
class SafeStreamHandler(logging.StreamHandler):
|
||||
"""Stream handler that forces UTF-8 encoding where supported"""
|
||||
|
||||
def __init__(self, stream=None):
|
||||
super().__init__(stream)
|
||||
# Try to set UTF-8 encoding on stdout/stderr if supported
|
||||
if hasattr(self.stream, 'reconfigure'):
|
||||
try:
|
||||
if platform.system() == "Windows":
|
||||
# On Windows, use errors='ignore'
|
||||
self.stream.reconfigure(encoding='utf-8', errors='ignore')
|
||||
else:
|
||||
# On Unix-like systems, use backslashreplace
|
||||
self.stream.reconfigure(encoding='utf-8', errors='backslashreplace')
|
||||
except (AttributeError, OSError):
|
||||
# If reconfigure is not available or fails, continue silently
|
||||
pass
|
||||
if platform.system() == "Windows":
|
||||
# Force UTF-8 encoding on Windows
|
||||
if hasattr(stream, 'reconfigure'):
|
||||
try:
|
||||
stream.reconfigure(encoding='utf-8', errors='ignore')
|
||||
except:
|
||||
pass
|
||||
|
||||
def setup_safe_logging(log_level=logging.INFO, log_file='logs/safe_logging.log'):
|
||||
"""Setup logging with SafeFormatter and UTF-8 encoding with enhanced persistence
|
||||
@ -165,3 +159,69 @@ def setup_safe_logging(log_level=logging.INFO, log_file='logs/safe_logging.log')
|
||||
# Register atexit handler for normal shutdown
|
||||
atexit.register(flush_all_logs)
|
||||
|
||||
def setup_training_logger(log_level=logging.INFO, log_file='logs/training.log'):
|
||||
"""Setup a separate training logger that writes to training.log
|
||||
|
||||
Args:
|
||||
log_level: Logging level (default: INFO)
|
||||
log_file: Path to training log file (default: logs/training.log)
|
||||
|
||||
Returns:
|
||||
logging.Logger: The training logger instance
|
||||
"""
|
||||
# Ensure logs directory exists
|
||||
log_path = Path(log_file)
|
||||
log_path.parent.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
# Create training logger
|
||||
training_logger = logging.getLogger('training')
|
||||
training_logger.setLevel(log_level)
|
||||
|
||||
# Clear existing handlers to avoid duplicates
|
||||
for handler in training_logger.handlers[:]:
|
||||
training_logger.removeHandler(handler)
|
||||
|
||||
# Create file handler for training logs
|
||||
try:
|
||||
encoding_kwargs = {
|
||||
"encoding": "utf-8",
|
||||
"errors": "ignore" if platform.system() == "Windows" else "backslashreplace"
|
||||
}
|
||||
|
||||
from logging.handlers import RotatingFileHandler
|
||||
file_handler = RotatingFileHandler(
|
||||
log_file,
|
||||
maxBytes=10*1024*1024, # 10MB max file size
|
||||
backupCount=5, # Keep 5 backup files
|
||||
**encoding_kwargs
|
||||
)
|
||||
file_handler.setFormatter(SafeFormatter(
|
||||
'%(asctime)s - %(name)s - %(levelname)s - %(message)s'
|
||||
))
|
||||
|
||||
# Force immediate flush for training logs
|
||||
class FlushingHandler(RotatingFileHandler):
|
||||
def emit(self, record):
|
||||
super().emit(record)
|
||||
self.flush() # Force flush after each log
|
||||
|
||||
file_handler = FlushingHandler(
|
||||
log_file,
|
||||
maxBytes=10*1024*1024,
|
||||
backupCount=5,
|
||||
**encoding_kwargs
|
||||
)
|
||||
file_handler.setFormatter(SafeFormatter(
|
||||
'%(asctime)s - %(name)s - %(levelname)s - %(message)s'
|
||||
))
|
||||
|
||||
training_logger.addHandler(file_handler)
|
||||
|
||||
except (OSError, IOError) as e:
|
||||
print(f"Warning: Could not create training log file {log_file}: {e}", file=sys.stderr)
|
||||
|
||||
# Prevent propagation to root logger to avoid duplicate logs
|
||||
training_logger.propagate = False
|
||||
|
||||
return training_logger
|
||||
|
||||
|
Reference in New Issue
Block a user