LogerinTxt.py 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110
  1. import traceback
  2. from datetime import datetime
  3. import os
  4. from pathlib import Path
  5. from unitls.settings import FilePath
  6. path = FilePath("save_url")
  7. class ErrorLogger:
  8. """
  9. 错误日志记录器(单例模式,固定配置)
  10. 功能:
  11. - 自动创建日志目录和文件
  12. - 限制单个日志文件大小
  13. - 自动滚动保留最近备份
  14. - 最新错误显示在最前面
  15. - 包含详细时间戳和错误堆栈
  16. """
  17. # 固定配置(类属性)
  18. _DEFAULT_FILENAME = "app_errors.log"
  19. _DEFAULT_LOG_DIR = Path(f"{path}\logs") # 默认存储目录
  20. _DEFAULT_MAX_SIZE_KB = 1024 # 默认1MB大小限制
  21. _DEFAULT_BACKUP_COUNT = 5 # 默认保留5个备份
  22. _instance = None # 单例实例
  23. def __new__(cls):
  24. if cls._instance is None:
  25. cls._instance = super().__new__(cls)
  26. cls._instance.__init__() # 确保初始化只执行一次
  27. return cls._instance
  28. def __init__(self):
  29. if not hasattr(self, '_initialized'): # 防止重复初始化
  30. self.filename = self._DEFAULT_LOG_DIR / self._DEFAULT_FILENAME
  31. self.max_size = self._DEFAULT_MAX_SIZE_KB * 1024
  32. self.backup_count = self._DEFAULT_BACKUP_COUNT
  33. self._ensure_directory_exists()
  34. self._ensure_file_exists()
  35. self._initialized = True
  36. def _ensure_directory_exists(self):
  37. """确保日志目录存在"""
  38. try:
  39. self._DEFAULT_LOG_DIR.mkdir(parents=True, exist_ok=True)
  40. except Exception as e:
  41. raise RuntimeError(f"无法创建日志目录 {self._DEFAULT_LOG_DIR}: {e}")
  42. def _ensure_file_exists(self):
  43. """确保日志文件存在"""
  44. try:
  45. if not self.filename.exists():
  46. with open(self.filename, 'w', encoding='utf-8') as f:
  47. f.write("") # 创建空文件
  48. except Exception as e:
  49. raise RuntimeError(f"无法创建日志文件 {self.filename}: {e}")
  50. def _rotate_files(self):
  51. """执行日志文件滚动"""
  52. if self.filename.exists() and os.path.getsize(self.filename) >= self.max_size:
  53. try:
  54. # 删除最旧的备份
  55. oldest = f"{self.filename}.{self.backup_count}"
  56. if os.path.exists(oldest):
  57. os.remove(oldest)
  58. # 重命名其他备份
  59. for i in range(self.backup_count - 1, 0, -1):
  60. src = f"{self.filename}.{i}"
  61. if os.path.exists(src):
  62. os.rename(src, f"{self.filename}.{i + 1}")
  63. # 重命名当前日志
  64. os.rename(self.filename, f"{self.filename}.1")
  65. # 创建新日志文件
  66. self._ensure_file_exists()
  67. except Exception as e:
  68. print(f"日志滚动失败: {e}")
  69. def log_error(self, error_msg=None):
  70. """
  71. 记录错误信息
  72. :param error_msg: 可以是Exception对象或任意可转换为字符串的内容
  73. """
  74. self._rotate_files()
  75. timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S.%f")[:-3] # 带毫秒的时间戳
  76. if isinstance(error_msg, Exception):
  77. error_details = "".join(traceback.format_exception(
  78. type(error_msg), error_msg, error_msg.__traceback__))
  79. else:
  80. error_details = str(error_msg) if error_msg else "Unknown error"
  81. log_entry = f"[{timestamp}]\n{error_details}\n{'=' * 50}\n"
  82. try:
  83. if os.path.exists(self.filename):
  84. with open(self.filename, 'r+', encoding='utf-8') as f:
  85. content = f.read()
  86. f.seek(0)
  87. f.write(log_entry + content)
  88. else:
  89. with open(self.filename, 'w', encoding='utf-8') as f:
  90. f.write(log_entry)
  91. except Exception as e:
  92. print(f"无法写入错误日志: {e}+\n+{error_msg}")
  93. # 创建单例实例(推荐直接使用这个实例)
  94. app_logger = ErrorLogger()