import traceback from datetime import datetime import os from pathlib import Path from unitls.settings import FilePath path = FilePath("save_url") class ErrorLogger: """ 错误日志记录器(单例模式,固定配置) 功能: - 自动创建日志目录和文件 - 限制单个日志文件大小 - 自动滚动保留最近备份 - 最新错误显示在最前面 - 包含详细时间戳和错误堆栈 """ # 固定配置(类属性) _DEFAULT_FILENAME = "app_errors.log" _DEFAULT_LOG_DIR = Path(f"{path}\logs") # 默认存储目录 _DEFAULT_MAX_SIZE_KB = 1024 # 默认1MB大小限制 _DEFAULT_BACKUP_COUNT = 5 # 默认保留5个备份 _instance = None # 单例实例 def __new__(cls): if cls._instance is None: cls._instance = super().__new__(cls) cls._instance.__init__() # 确保初始化只执行一次 return cls._instance def __init__(self): if not hasattr(self, '_initialized'): # 防止重复初始化 self.filename = self._DEFAULT_LOG_DIR / self._DEFAULT_FILENAME self.max_size = self._DEFAULT_MAX_SIZE_KB * 1024 self.backup_count = self._DEFAULT_BACKUP_COUNT self._ensure_directory_exists() self._ensure_file_exists() self._initialized = True def _ensure_directory_exists(self): """确保日志目录存在""" try: self._DEFAULT_LOG_DIR.mkdir(parents=True, exist_ok=True) except Exception as e: raise RuntimeError(f"无法创建日志目录 {self._DEFAULT_LOG_DIR}: {e}") def _ensure_file_exists(self): """确保日志文件存在""" try: if not self.filename.exists(): with open(self.filename, 'w', encoding='utf-8') as f: f.write("") # 创建空文件 except Exception as e: raise RuntimeError(f"无法创建日志文件 {self.filename}: {e}") def _rotate_files(self): """执行日志文件滚动""" if self.filename.exists() and os.path.getsize(self.filename) >= self.max_size: try: # 删除最旧的备份 oldest = f"{self.filename}.{self.backup_count}" if os.path.exists(oldest): os.remove(oldest) # 重命名其他备份 for i in range(self.backup_count - 1, 0, -1): src = f"{self.filename}.{i}" if os.path.exists(src): os.rename(src, f"{self.filename}.{i + 1}") # 重命名当前日志 os.rename(self.filename, f"{self.filename}.1") # 创建新日志文件 self._ensure_file_exists() except Exception as e: print(f"日志滚动失败: {e}") def log_error(self, error_msg=None): """ 记录错误信息 :param error_msg: 可以是Exception对象或任意可转换为字符串的内容 """ self._rotate_files() timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S.%f")[:-3] # 带毫秒的时间戳 if isinstance(error_msg, Exception): error_details = "".join(traceback.format_exception( type(error_msg), error_msg, error_msg.__traceback__)) else: error_details = str(error_msg) if error_msg else "Unknown error" log_entry = f"[{timestamp}]\n{error_details}\n{'=' * 50}\n" try: if os.path.exists(self.filename): with open(self.filename, 'r+', encoding='utf-8') as f: content = f.read() f.seek(0) f.write(log_entry + content) else: with open(self.filename, 'w', encoding='utf-8') as f: f.write(log_entry) except Exception as e: print(f"无法写入错误日志: {e}+\n+{error_msg}") # 创建单例实例(推荐直接使用这个实例) app_logger = ErrorLogger()