2026-01-30 18:30:05 +08:00
|
|
|
|
# -*- coding: utf-8 -*-
|
|
|
|
|
|
"""
|
|
|
|
|
|
日志管理模块
|
|
|
|
|
|
统一管理日志配置和输出
|
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
|
|
import os
|
|
|
|
|
|
import logging
|
|
|
|
|
|
import sys
|
|
|
|
|
|
from datetime import datetime
|
|
|
|
|
|
from typing import Optional
|
|
|
|
|
|
|
|
|
|
|
|
# 日志目录
|
2026-02-05 18:58:59 +08:00
|
|
|
|
LOG_DIR = os.path.join(os.path.dirname(__file__), "logs")
|
2026-01-30 18:30:05 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def setup_logger(
|
|
|
|
|
|
name: str = "tag_derive",
|
|
|
|
|
|
level: str = "INFO",
|
|
|
|
|
|
log_file: Optional[str] = None,
|
|
|
|
|
|
console: bool = True
|
|
|
|
|
|
) -> logging.Logger:
|
|
|
|
|
|
"""
|
|
|
|
|
|
设置并返回logger
|
|
|
|
|
|
|
|
|
|
|
|
Args:
|
|
|
|
|
|
name: logger名称
|
|
|
|
|
|
level: 日志级别 (DEBUG, INFO, WARNING, ERROR, CRITICAL)
|
|
|
|
|
|
log_file: 日志文件路径,None则不写入文件
|
|
|
|
|
|
console: 是否输出到控制台
|
|
|
|
|
|
"""
|
|
|
|
|
|
logger = logging.getLogger(name)
|
|
|
|
|
|
|
|
|
|
|
|
# 避免重复添加handler
|
|
|
|
|
|
if logger.handlers:
|
|
|
|
|
|
return logger
|
|
|
|
|
|
|
|
|
|
|
|
logger.setLevel(getattr(logging, level.upper(), logging.INFO))
|
|
|
|
|
|
|
|
|
|
|
|
# 日志格式
|
|
|
|
|
|
formatter = logging.Formatter(
|
|
|
|
|
|
fmt="%(asctime)s [%(levelname)s] %(name)s: %(message)s",
|
|
|
|
|
|
datefmt="%Y-%m-%d %H:%M:%S"
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
# 控制台输出
|
|
|
|
|
|
if console:
|
|
|
|
|
|
console_handler = logging.StreamHandler(sys.stdout)
|
|
|
|
|
|
console_handler.setFormatter(formatter)
|
|
|
|
|
|
logger.addHandler(console_handler)
|
|
|
|
|
|
|
|
|
|
|
|
# 文件输出
|
|
|
|
|
|
if log_file:
|
|
|
|
|
|
# 确保日志目录存在
|
|
|
|
|
|
os.makedirs(os.path.dirname(log_file), exist_ok=True)
|
|
|
|
|
|
file_handler = logging.FileHandler(log_file, encoding="utf-8")
|
|
|
|
|
|
file_handler.setFormatter(formatter)
|
|
|
|
|
|
logger.addHandler(file_handler)
|
|
|
|
|
|
|
|
|
|
|
|
return logger
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def get_default_log_file() -> str:
|
|
|
|
|
|
"""获取默认日志文件路径(按日期)"""
|
|
|
|
|
|
os.makedirs(LOG_DIR, exist_ok=True)
|
|
|
|
|
|
date_str = datetime.now().strftime("%Y%m%d")
|
|
|
|
|
|
return os.path.join(LOG_DIR, f"tag_derive_{date_str}.log")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# 默认logger实例
|
|
|
|
|
|
_default_logger = None
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def get_logger(name: str = "tag_derive") -> logging.Logger:
|
|
|
|
|
|
"""获取logger实例"""
|
|
|
|
|
|
global _default_logger
|
|
|
|
|
|
if _default_logger is None:
|
|
|
|
|
|
_default_logger = setup_logger(
|
|
|
|
|
|
name=name,
|
|
|
|
|
|
level="INFO",
|
|
|
|
|
|
log_file=get_default_log_file(),
|
|
|
|
|
|
console=True
|
|
|
|
|
|
)
|
|
|
|
|
|
return _default_logger
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class LogMixin:
|
|
|
|
|
|
"""日志混入类,为类提供日志能力"""
|
|
|
|
|
|
|
|
|
|
|
|
@property
|
|
|
|
|
|
def logger(self) -> logging.Logger:
|
|
|
|
|
|
if not hasattr(self, '_logger'):
|
|
|
|
|
|
self._logger = get_logger(self.__class__.__name__)
|
|
|
|
|
|
return self._logger
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# ============== 便捷函数 ==============
|
|
|
|
|
|
def log_info(msg: str, *args):
|
|
|
|
|
|
get_logger().info(msg, *args)
|
|
|
|
|
|
|
|
|
|
|
|
def log_error(msg: str, *args):
|
|
|
|
|
|
get_logger().error(msg, *args)
|
|
|
|
|
|
|
|
|
|
|
|
def log_warning(msg: str, *args):
|
|
|
|
|
|
get_logger().warning(msg, *args)
|
|
|
|
|
|
|
|
|
|
|
|
def log_debug(msg: str, *args):
|
|
|
|
|
|
get_logger().debug(msg, *args)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if __name__ == "__main__":
|
|
|
|
|
|
# 测试日志
|
|
|
|
|
|
logger = get_logger()
|
|
|
|
|
|
logger.info("日志系统初始化成功")
|
|
|
|
|
|
logger.debug("这是DEBUG日志")
|
|
|
|
|
|
logger.warning("这是WARNING日志")
|
|
|
|
|
|
logger.error("这是ERROR日志")
|
|
|
|
|
|
print(f"日志文件: {get_default_log_file()}")
|