From 519ad08b67ffbee94a730ce0858311c20ceaecf5 Mon Sep 17 00:00:00 2001 From: mckay Date: Sat, 23 Nov 2024 20:19:08 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=AE=8C=E5=96=84log=E8=AE=B0=E5=BD=95?= =?UTF-8?q?=EF=BC=8C=E5=8F=AF=E4=BB=A5=E6=98=BE=E7=A4=BA=E6=8A=A5=E9=94=99?= =?UTF-8?q?=E4=BD=8D=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- brep2sdf/utils/logger.py | 164 +++++++++++++++++++++++++++++++-------- 1 file changed, 132 insertions(+), 32 deletions(-) diff --git a/brep2sdf/utils/logger.py b/brep2sdf/utils/logger.py index f892c41..7de2ae3 100644 --- a/brep2sdf/utils/logger.py +++ b/brep2sdf/utils/logger.py @@ -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 == ''): + 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 == ''): + 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的便捷函数"""