Files
Orbitin/src/logging_config.py

172 lines
5.1 KiB
Python
Raw Normal View History

#!/usr/bin/env python3
"""
统一日志配置模块
提供统一的日志配置避免各模块自行配置
支持按日期分片存储日志
"""
import os
import logging
import sys
from datetime import datetime
from logging.handlers import RotatingFileHandler, TimedRotatingFileHandler
from typing import Optional
from src.config import config
def setup_logging(
log_file: Optional[str] = None,
console_level: int = logging.INFO,
file_level: int = logging.DEBUG,
use_date_split: bool = True,
date_folder_format: str = "%Y-%m", # 按月份分文件夹
max_bytes: int = 10 * 1024 * 1024, # 10MB
backup_count: int = 5
) -> logging.Logger:
"""
配置统一的日志系统
参数:
log_file: 日志文件路径如果为None则使用默认路径
console_level: 控制台日志级别
file_level: 文件日志级别
use_date_split: 是否使用日期分片
date_folder_format: 日期文件夹格式默认按月份 logs/2025-12/
max_bytes: 单个日志文件最大大小
backup_count: 备份文件数量
返回:
配置好的根日志器
"""
# 获取当前日期用于构建路径
now = datetime.now()
if log_file is None:
log_dir = 'logs'
if use_date_split:
# 按日期分片logs/2025-12/2025-12-30.log
date_folder = now.strftime(date_folder_format)
log_dir = os.path.join('logs', date_folder)
log_file = os.path.join(log_dir, now.strftime('%Y-%m-%d.log'))
else:
log_file = os.path.join(log_dir, 'app.log')
else:
log_dir = os.path.dirname(log_file)
if log_dir and not os.path.exists(log_dir):
os.makedirs(log_dir, exist_ok=True)
# 获取根日志器
logger = logging.getLogger()
logger.setLevel(logging.DEBUG) # 根日志器设置为最低级别
# 清除现有handler避免重复添加
logger.handlers.clear()
# 控制台handler
console_handler = logging.StreamHandler(sys.stdout)
console_handler.setLevel(console_level)
console_formatter = logging.Formatter(
'%(asctime)s - %(name)s - %(levelname)s - %(message)s',
datefmt='%Y-%m-%d %H:%M:%S'
)
console_handler.setFormatter(console_formatter)
logger.addHandler(console_handler)
# 文件handler日期分片或大小轮转
if use_date_split:
# 使用TimedRotatingFileHandler每天午夜轮转
file_handler = TimedRotatingFileHandler(
log_file,
when='midnight',
interval=1,
backupCount=backup_count,
encoding='utf-8',
atTime=datetime.strptime('00:00:00', '%H:%M:%S')
)
logger.info(f"日志系统已初始化,使用日期分片: {log_file}")
else:
# 使用RotatingFileHandler按大小轮转
file_handler = RotatingFileHandler(
log_file,
maxBytes=max_bytes,
backupCount=backup_count,
encoding='utf-8'
)
logger.info(f"日志系统已初始化,使用大小轮转: {log_file}")
file_handler.setLevel(file_level)
file_formatter = logging.Formatter(
'%(asctime)s - %(name)s - %(levelname)s - %(filename)s:%(lineno)d - %(message)s',
datefmt='%Y-%m-%d %H:%M:%S'
)
file_handler.setFormatter(file_formatter)
logger.addHandler(file_handler)
# 设置第三方库的日志级别
logging.getLogger('urllib3').setLevel(logging.WARNING)
logging.getLogger('requests').setLevel(logging.WARNING)
logger.info(f"控制台日志级别: {logging.getLevelName(console_level)}")
logger.info(f"文件日志级别: {logging.getLevelName(file_level)}")
return logger
def get_logger(name: str) -> logging.Logger:
"""
获取指定名称的日志器
参数:
name: 日志器名称通常使用 __name__
返回:
配置好的日志器
"""
return logging.getLogger(name)
# 自动初始化日志系统
if not logging.getLogger().handlers:
# 只有在没有handler时才初始化避免重复初始化
setup_logging()
# 便捷函数
def info(msg: str, *args, **kwargs):
"""记录INFO级别日志"""
logging.info(msg, *args, **kwargs)
def warning(msg: str, *args, **kwargs):
"""记录WARNING级别日志"""
logging.warning(msg, *args, **kwargs)
def error(msg: str, *args, **kwargs):
"""记录ERROR级别日志"""
logging.error(msg, *args, **kwargs)
def debug(msg: str, *args, **kwargs):
"""记录DEBUG级别日志"""
logging.debug(msg, *args, **kwargs)
def exception(msg: str, *args, **kwargs):
"""记录异常日志"""
logging.exception(msg, *args, **kwargs)
if __name__ == '__main__':
# 测试日志配置
logger = get_logger(__name__)
logger.info("测试INFO日志")
logger.warning("测试WARNING日志")
logger.error("测试ERROR日志")
logger.debug("测试DEBUG日志")
try:
raise ValueError("测试异常")
except ValueError as e:
logger.exception("捕获到异常: %s", e)