"""
Logger Configuration Module
Provides unified logging management with output to both console and file
"""
import os
import sys
import logging
from datetime import datetime
from logging.handlers import RotatingFileHandler
def _ensure_utf8_stdout():
"""
Ensure stdout/stderr use UTF-8 encoding
Solves Windows console Chinese character encoding issue
"""
if sys.platform == 'win32':
# Reconfigure standard output to UTF-8 on Windows
if hasattr(sys.stdout, 'reconfigure'):
sys.stdout.reconfigure(encoding='utf-8', errors='replace')
if hasattr(sys.stderr, 'reconfigure'):
sys.stderr.reconfigure(encoding='utf-8', errors='replace')
# Log directory
LOG_DIR = os.path.join(os.path.dirname(os.path.dirname(os.path.dirname(__file__))), 'logs')
def setup_logger(name: str = 'mirofish', level: int = logging.DEBUG) -> logging.Logger:
"""
Setup logger
Args:
name: Logger name
level: Log level
Returns:
Configured logger
"""
# Ensure log directory exists
os.makedirs(LOG_DIR, exist_ok=True)
# Create logger
logger = logging.getLogger(name)
logger.setLevel(level)
# Prevent logs from propagating to root logger to avoid duplicate output
logger.propagate = False
# If handlers already exist, don't add duplicates
if logger.handlers:
return logger
# Log formats
detailed_formatter = logging.Formatter(
'[%(asctime)s] %(levelname)s [%(name)s.%(funcName)s:%(lineno)d] %(message)s',
datefmt='%Y-%m-%d %H:%M:%S'
)
simple_formatter = logging.Formatter(
'[%(asctime)s] %(levelname)s: %(message)s',
datefmt='%H:%M:%S'
)
# 1. File handler - detailed logs (named by date, with rotation)
log_filename = datetime.now().strftime('%Y-%m-%d') + '.log'
file_handler = RotatingFileHandler(
os.path.join(LOG_DIR, log_filename),
maxBytes=10 * 1024 * 1024, # 10MB
backupCount=5,
encoding='utf-8'
)
file_handler.setLevel(logging.DEBUG)
file_handler.setFormatter(detailed_formatter)
# 2. Console handler - concise logs (INFO and above)
# Ensure UTF-8 encoding on Windows to avoid Chinese character issues
_ensure_utf8_stdout()
console_handler = logging.StreamHandler(sys.stdout)
console_handler.setLevel(logging.INFO)
console_handler.setFormatter(simple_formatter)
# Add handlers
logger.addHandler(file_handler)
logger.addHandler(console_handler)
return logger
def get_logger(name: str = 'mirofish') -> logging.Logger:
"""
Get logger (create if not exists)
Args:
name: Logger name
Returns:
Logger instance
"""
logger = logging.getLogger(name)
if not logger.handlers:
return setup_logger(name)
return logger
# Create default logger
logger = setup_logger()
# Convenience functions
def debug(msg, *args, **kwargs):
logger.debug(msg, *args, **kwargs)
def info(msg, *args, **kwargs):
logger.info(msg, *args, **kwargs)
def warning(msg, *args, **kwargs):
logger.warning(msg, *args, **kwargs)
def error(msg, *args, **kwargs):
logger.error(msg, *args, **kwargs)
def critical(msg, *args, **kwargs):
logger.critical(msg, *args, **kwargs)