Files
intelligence_system/utils/logger.py
T
2025-08-05 17:13:19 +08:00

130 lines
4.0 KiB
Python

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
跨平台日志工具模块
功能:
1. 自动适配不同操作系统的日志路径
2. 支持中文等非ASCII字符
3. 日志文件自动按日期分割
4. 控制台与文件双输出
"""
import os
import sys
import logging
from logging.handlers import TimedRotatingFileHandler
from datetime import datetime
import platform
class CrossPlatformLogger:
def __init__(self, name="intelligence_system"):
"""
初始化跨平台日志系统
参数:
name: 日志名称(用于创建日志文件夹)
"""
self.system = platform.system().lower()
self.logger = logging.getLogger(name)
self.logger.setLevel(logging.INFO)
# 确保日志目录存在
self.log_dir = self._get_log_dir(name)
os.makedirs(self.log_dir, exist_ok=True)
# 配置日志格式
formatter = logging.Formatter(
'%(asctime)s - %(name)s - %(levelname)s - %(message)s',
datefmt='%Y-%m-%d %H:%M:%S'
)
# 控制台处理器
self._setup_console_handler(formatter)
# 文件处理器(按天分割)
self._setup_file_handler(formatter)
# 处理未捕获的异常
sys.excepthook = self.handle_uncaught_exception
def _get_log_dir(self, name: str) -> str:
"""获取适合当前平台的日志目录路径"""
if self.system == 'windows':
base_dir = os.path.join(os.environ['APPDATA'], name)
elif self.system == 'darwin': # macOS
base_dir = os.path.expanduser(f"~/Library/Logs/{name}")
else: # Linux及其他Unix-like系统
base_dir = f"/var/log/{name}" if os.access("/var/log", os.W_OK) \
else os.path.expanduser(f"~/.local/share/{name}")
return base_dir
def _setup_console_handler(self, formatter: logging.Formatter):
"""配置控制台输出(兼容不同终端的编码)"""
console = logging.StreamHandler()
# Windows终端特殊处理
if self.system == 'windows' and not sys.stdout.isatty():
import colorama
try:
colorama.init()
except ImportError:
pass
# 解决Windows控制台编码问题
if sys.stdout.encoding != 'utf-8':
import io
sys.stdout = io.TextIOWrapper(
sys.stdout.buffer,
encoding='utf-8',
errors='replace'
)
console.setFormatter(formatter)
self.logger.addHandler(console)
def _setup_file_handler(self, formatter: logging.Formatter):
"""配置日志文件输出(UTF-8编码)"""
log_file = os.path.join(
self.log_dir,
f"{datetime.now().strftime('%Y%m%d')}.log"
)
# 使用TimedRotatingFileHandler实现日志分割
file_handler = TimedRotatingFileHandler(
filename=log_file,
when='midnight', # 每天午夜分割
encoding='utf-8',
backupCount=30 # 保留30天日志
)
file_handler.setFormatter(formatter)
self.logger.addHandler(file_handler)
def handle_uncaught_exception(self, exc_type, exc_value, exc_traceback):
"""全局异常捕获"""
self.logger.error(
"未捕获的异常:",
exc_info=(exc_type, exc_value, exc_traceback)
)
@staticmethod
def get_logger(name: str = None) -> logging.Logger:
"""获取配置好的日志实例"""
return CrossPlatformLogger(name).logger
def setup_logging(name: str = "intelligence_system"):
"""快速配置日志(兼容旧代码)"""
return CrossPlatformLogger(name).logger
# 测试代码
if __name__ == "__main__":
logger = CrossPlatformLogger().logger
logger.info("这是一条info日志(包含中文测试)")
try:
1 / 0
except Exception as e:
logger.error("除零错误示例", exc_info=True)