|
|
@ -4,6 +4,59 @@ import logging |
|
|
|
import traceback |
|
|
|
from datetime import datetime |
|
|
|
from brep2sdf.config.default_config import get_default_config |
|
|
|
from functools import wraps |
|
|
|
import time |
|
|
|
|
|
|
|
class ColoredFormatter(logging.Formatter): |
|
|
|
"""自定义彩色格式化器""" |
|
|
|
|
|
|
|
# ANSI转义序列颜色代码 |
|
|
|
COLORS = { |
|
|
|
'DEBUG': '\033[36m', # 青色 |
|
|
|
'INFO': '\033[32m', # 绿色 |
|
|
|
'WARNING': '\033[33m', # 黄色 |
|
|
|
'ERROR': '\033[31m', # 红色 |
|
|
|
'CRITICAL': '\033[35m', # 紫色 |
|
|
|
'RESET': '\033[0m' # 重置 |
|
|
|
} |
|
|
|
|
|
|
|
def format(self, record): |
|
|
|
# 确保record有caller_info属性 |
|
|
|
if not hasattr(record, 'caller_info'): |
|
|
|
record.caller_info = self._get_caller_info() |
|
|
|
|
|
|
|
# 添加时间戳颜色 |
|
|
|
time_color = '\033[34m' # 蓝色 |
|
|
|
record.colored_time = f"{time_color}{self.formatTime(record)}\033[0m" |
|
|
|
|
|
|
|
# 添加日志级别颜色 |
|
|
|
level_color = self.COLORS.get(record.levelname, self.COLORS['RESET']) |
|
|
|
record.colored_levelname = f"{level_color}{record.levelname:8}\033[0m" |
|
|
|
|
|
|
|
# 添加文件信息颜色 |
|
|
|
file_color = '\033[36m' # 青色 |
|
|
|
record.colored_file_info = f"{file_color}{record.caller_info}\033[0m" |
|
|
|
|
|
|
|
return super().format(record) |
|
|
|
|
|
|
|
def _get_caller_info(self): |
|
|
|
"""获取调用者信息""" |
|
|
|
try: |
|
|
|
# 获取调用栈 |
|
|
|
stack = traceback.extract_stack() |
|
|
|
|
|
|
|
# 从后往前遍历调用栈,跳过日志模块的调用 |
|
|
|
for frame in reversed(stack[:-1]): |
|
|
|
filename = os.path.basename(frame.filename) |
|
|
|
# 跳过日志模块相关的文件 |
|
|
|
if not (filename == 'logger.py' or |
|
|
|
filename.startswith('logging') or |
|
|
|
filename == '<string>'): |
|
|
|
return f"{filename}:{frame.name}:{frame.lineno}" |
|
|
|
|
|
|
|
return "Unknown:Unknown:0" |
|
|
|
except Exception: |
|
|
|
return "Unknown:Unknown:0" |
|
|
|
|
|
|
|
class BRepLogger: |
|
|
|
_instance = None |
|
|
@ -14,6 +67,67 @@ class BRepLogger: |
|
|
|
cls._instance._initialize_logger(config) |
|
|
|
return cls._instance |
|
|
|
|
|
|
|
def _get_caller_info(self, stack_offset=2): |
|
|
|
"""获取调用者信息 |
|
|
|
Args: |
|
|
|
stack_offset: 需要跳过的调用栈层数 |
|
|
|
""" |
|
|
|
try: |
|
|
|
# 获取调用栈 |
|
|
|
stack = traceback.extract_stack() |
|
|
|
|
|
|
|
# 从后往前遍历调用栈,跳过日志模块的调用 |
|
|
|
for frame in reversed(stack[:-stack_offset]): |
|
|
|
filename = os.path.basename(frame.filename) |
|
|
|
# 跳过日志模块相关的文件 |
|
|
|
if not (filename == 'logger.py' or |
|
|
|
filename.startswith('logging') or |
|
|
|
filename == '<string>'): |
|
|
|
return f"{filename}:{frame.name}:{frame.lineno}" |
|
|
|
|
|
|
|
return "Unknown:Unknown:0" |
|
|
|
except Exception: |
|
|
|
return "Unknown:Unknown:0" |
|
|
|
|
|
|
|
def _log(self, level, msg, **kwargs): |
|
|
|
"""统一的日志记录方法""" |
|
|
|
# 创建LogRecord |
|
|
|
record = logging.LogRecord( |
|
|
|
name=self.logger.name, |
|
|
|
level=level, |
|
|
|
pathname=__file__, |
|
|
|
lineno=0, |
|
|
|
msg=msg, |
|
|
|
args=(), |
|
|
|
exc_info=kwargs.get('exc_info'), |
|
|
|
) |
|
|
|
|
|
|
|
# 获取真实的调用者信息 |
|
|
|
record.caller_info = self._get_caller_info(3) # 增加stack_offset以跳过更多调用层 |
|
|
|
|
|
|
|
# 处理日志记录 |
|
|
|
self.logger.handle(record) |
|
|
|
|
|
|
|
def debug(self, msg): |
|
|
|
"""调试信息""" |
|
|
|
self._log(logging.DEBUG, msg) |
|
|
|
|
|
|
|
def info(self, msg): |
|
|
|
"""信息""" |
|
|
|
self._log(logging.INFO, msg) |
|
|
|
|
|
|
|
def warning(self, msg): |
|
|
|
"""警告信息""" |
|
|
|
self._log(logging.WARNING, msg) |
|
|
|
|
|
|
|
def error(self, msg, include_trace=True): |
|
|
|
"""错误信息""" |
|
|
|
self._log(logging.ERROR, msg, exc_info=include_trace) |
|
|
|
|
|
|
|
def exception(self, msg): |
|
|
|
"""异常信息""" |
|
|
|
self._log(logging.ERROR, msg, exc_info=True) |
|
|
|
|
|
|
|
def _initialize_logger(self, config=None): |
|
|
|
"""初始化日志记录器""" |
|
|
|
if config is None: |
|
|
@ -32,10 +146,11 @@ class BRepLogger: |
|
|
|
return |
|
|
|
|
|
|
|
# 创建格式化器 |
|
|
|
simple_formatter = logging.Formatter('%(levelname)s - %(message)s') |
|
|
|
detailed_formatter = logging.Formatter( |
|
|
|
'%(asctime)s - %(levelname)s - ' |
|
|
|
'%(filename)s:%(lineno)d in %(funcName)s - %(message)s' |
|
|
|
console_formatter = ColoredFormatter( |
|
|
|
'%(colored_time)s | %(colored_levelname)s | %(colored_file_info)s - %(message)s' |
|
|
|
) |
|
|
|
file_formatter = logging.Formatter( |
|
|
|
'%(asctime)s | %(levelname)-8s | %(caller_info)s - %(message)s' |
|
|
|
) |
|
|
|
|
|
|
|
# 创建文件处理器 (详细日志) |
|
|
@ -43,12 +158,12 @@ class BRepLogger: |
|
|
|
log_file = os.path.join(log_dir, f'brep2sdf_{current_time}.log') |
|
|
|
file_handler = logging.FileHandler(log_file, encoding='utf-8') |
|
|
|
file_handler.setLevel(getattr(logging, config.log.file_level.upper())) |
|
|
|
file_handler.setFormatter(detailed_formatter) |
|
|
|
file_handler.setFormatter(file_formatter) |
|
|
|
|
|
|
|
# 创建控制台处理器 (简略日志) |
|
|
|
console_handler = logging.StreamHandler(sys.stdout) |
|
|
|
console_handler.setLevel(getattr(logging, config.log.console_level.upper())) |
|
|
|
console_handler.setFormatter(simple_formatter) |
|
|
|
console_handler.setFormatter(console_formatter) |
|
|
|
|
|
|
|
# 添加处理器 |
|
|
|
self.logger.addHandler(file_handler) |
|
|
@ -61,32 +176,17 @@ class BRepLogger: |
|
|
|
self.logger.info("BRep Logger initialized") |
|
|
|
self.logger.debug(f"Log file: {log_file}") |
|
|
|
|
|
|
|
def debug(self, msg): |
|
|
|
"""调试信息""" |
|
|
|
if self.include_trace: |
|
|
|
caller = traceback.extract_stack()[-2] |
|
|
|
filename = os.path.basename(caller.filename) |
|
|
|
self.logger.debug(f"{msg} (in {filename})") |
|
|
|
else: |
|
|
|
self.logger.debug(msg) |
|
|
|
|
|
|
|
def info(self, msg): |
|
|
|
self.logger.info(msg) |
|
|
|
|
|
|
|
def warning(self, msg): |
|
|
|
self.logger.warning(msg) |
|
|
|
|
|
|
|
def error(self, msg, include_trace=None): |
|
|
|
"""错误信息""" |
|
|
|
include_trace = self.include_trace if include_trace is None else include_trace |
|
|
|
if include_trace: |
|
|
|
self.logger.error(msg, exc_info=True, stack_info=True) |
|
|
|
else: |
|
|
|
self.logger.error(msg) |
|
|
|
|
|
|
|
def exception(self, msg): |
|
|
|
"""异常信息""" |
|
|
|
self.logger.exception(msg) |
|
|
|
def timeit(func): |
|
|
|
"""计时装饰器""" |
|
|
|
@wraps(func) |
|
|
|
def wrapper(*args, **kwargs): |
|
|
|
start_time = time.perf_counter() |
|
|
|
result = func(*args, **kwargs) |
|
|
|
end_time = time.perf_counter() |
|
|
|
total_time = end_time - start_time |
|
|
|
logger.debug(f"{func.__name__} took {total_time:.4f} seconds") |
|
|
|
return result |
|
|
|
return wrapper |
|
|
|
|
|
|
|
def setup_logger(config=None): |
|
|
|
"""创建logger的便捷函数""" |
|
|
|