Files
lowkey_backtest/engine/logging_config.py

125 lines
3.4 KiB
Python

"""
Centralized logging configuration for the backtest engine.
Provides colored console output and rotating file logs.
"""
import logging
import sys
from logging.handlers import RotatingFileHandler
from pathlib import Path
# ANSI color codes for terminal output
class Colors:
"""ANSI escape codes for colored terminal output."""
RESET = "\033[0m"
BOLD = "\033[1m"
# Log level colors
DEBUG = "\033[36m" # Cyan
INFO = "\033[32m" # Green
WARNING = "\033[33m" # Yellow
ERROR = "\033[31m" # Red
CRITICAL = "\033[35m" # Magenta
class ColoredFormatter(logging.Formatter):
"""
Custom formatter that adds colors to log level names in terminal output.
"""
LEVEL_COLORS = {
logging.DEBUG: Colors.DEBUG,
logging.INFO: Colors.INFO,
logging.WARNING: Colors.WARNING,
logging.ERROR: Colors.ERROR,
logging.CRITICAL: Colors.CRITICAL,
}
def __init__(self, fmt: str = None, datefmt: str = None):
super().__init__(fmt, datefmt)
def format(self, record: logging.LogRecord) -> str:
# Save original levelname
original_levelname = record.levelname
# Add color to levelname
color = self.LEVEL_COLORS.get(record.levelno, Colors.RESET)
record.levelname = f"{color}{record.levelname}{Colors.RESET}"
# Format the message
result = super().format(record)
# Restore original levelname
record.levelname = original_levelname
return result
def setup_logging(
log_dir: str = "logs",
log_level: int = logging.INFO,
console_level: int = logging.INFO,
max_bytes: int = 5 * 1024 * 1024, # 5MB
backup_count: int = 3
) -> None:
"""
Configure logging for the application.
Args:
log_dir: Directory for log files
log_level: File logging level
console_level: Console logging level
max_bytes: Max size per log file before rotation
backup_count: Number of backup files to keep
"""
log_path = Path(log_dir)
log_path.mkdir(parents=True, exist_ok=True)
# Get root logger
root_logger = logging.getLogger()
root_logger.setLevel(logging.DEBUG) # Capture all, handlers filter
# Clear existing handlers
root_logger.handlers.clear()
# Console handler with colors
console_handler = logging.StreamHandler(sys.stdout)
console_handler.setLevel(console_level)
console_fmt = ColoredFormatter(
fmt="[%(asctime)s] %(levelname)s - %(message)s",
datefmt="%H:%M:%S"
)
console_handler.setFormatter(console_fmt)
root_logger.addHandler(console_handler)
# File handler with rotation
file_handler = RotatingFileHandler(
log_path / "backtest.log",
maxBytes=max_bytes,
backupCount=backup_count,
encoding="utf-8"
)
file_handler.setLevel(log_level)
file_fmt = logging.Formatter(
fmt="%(asctime)s - %(name)s - %(levelname)s - %(message)s",
datefmt="%Y-%m-%d %H:%M:%S"
)
file_handler.setFormatter(file_fmt)
root_logger.addHandler(file_handler)
def get_logger(name: str) -> logging.Logger:
"""
Get a logger instance for the given module name.
Args:
name: Module name (typically __name__)
Returns:
Configured logger instance
"""
return logging.getLogger(name)