|
@@ -0,0 +1,96 @@
|
|
|
+import os
|
|
|
+import threading
|
|
|
+from datetime import datetime, timezone, timedelta
|
|
|
+
|
|
|
+class Logger:
|
|
|
+ def __init__(self, module_name, log_path="./logs", max_log_size=5*1024*1024, max_log_files=10, log_lvl=1):
|
|
|
+ """
|
|
|
+ :param module_name: 模块名,日志文件前缀
|
|
|
+ :param log_path: 日志目录
|
|
|
+ :param max_log_size: 单个日志文件最大字节数
|
|
|
+ :param max_log_files: 保留的最大日志文件数
|
|
|
+ :param log_lvl: 日志等级(0=DEBUG, 1=INFO, 2=WARN, 3=ERROR)
|
|
|
+ """
|
|
|
+ self.module_name = module_name
|
|
|
+ self.log_path = log_path
|
|
|
+ self.max_log_size = max_log_size
|
|
|
+ self.max_log_files = max_log_files
|
|
|
+ self.log_lvl = log_lvl
|
|
|
+
|
|
|
+ os.makedirs(log_path, exist_ok=True)
|
|
|
+
|
|
|
+ self.log_file = os.path.join(log_path, f"{module_name}.log")
|
|
|
+ self.lock = threading.Lock()
|
|
|
+
|
|
|
+ # 维护文件大小计数器
|
|
|
+ if os.path.exists(self.log_file):
|
|
|
+ self.cur_size = os.path.getsize(self.log_file)
|
|
|
+ else:
|
|
|
+ self.cur_size = 0
|
|
|
+
|
|
|
+ def _get_bj_time_ms(self):
|
|
|
+ tz = timezone(timedelta(hours=8)) # 北京时间
|
|
|
+ now = datetime.now(tz)
|
|
|
+ return now.strftime("%Y-%m-%d %H:%M:%S.%f")[:-3]
|
|
|
+
|
|
|
+ def _rotate_log(self):
|
|
|
+ """日志切分"""
|
|
|
+ if os.path.exists(self.log_file) and self.cur_size >= self.max_log_size:
|
|
|
+ timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
|
|
|
+ new_log_file = os.path.join(self.log_path, f"{self.module_name}_{timestamp}.log")
|
|
|
+ os.rename(self.log_file, new_log_file)
|
|
|
+ self.cur_size = 0
|
|
|
+ self._manage_log_files()
|
|
|
+
|
|
|
+ def _manage_log_files(self):
|
|
|
+ """控制日志文件数量"""
|
|
|
+ log_files = sorted(
|
|
|
+ (f for f in os.listdir(self.log_path) if f.endswith(".log")),
|
|
|
+ key=lambda x: os.path.getctime(os.path.join(self.log_path, x))
|
|
|
+ )
|
|
|
+ while len(log_files) > self.max_log_files:
|
|
|
+ oldest_file = log_files.pop(0)
|
|
|
+ os.remove(os.path.join(self.log_path, oldest_file))
|
|
|
+
|
|
|
+ def _log(self, lvl_name, text):
|
|
|
+ with self.lock:
|
|
|
+ self._rotate_log()
|
|
|
+ formatted_now = self._get_bj_time_ms()
|
|
|
+ line = f"[{formatted_now}][{lvl_name}]: {text}\n"
|
|
|
+ with open(self.log_file, "a", encoding="utf-8") as f:
|
|
|
+ f.write(line)
|
|
|
+ self.cur_size += len(line.encode("utf-8"))
|
|
|
+
|
|
|
+ # ========== 对外接口 ==========
|
|
|
+ def LOGDBG(self, text):
|
|
|
+ if self.log_lvl <= 0:
|
|
|
+ self._log("DEBUG", text)
|
|
|
+
|
|
|
+ def LOGINFO(self, text):
|
|
|
+ if self.log_lvl <= 1:
|
|
|
+ self._log("INFO", text)
|
|
|
+
|
|
|
+ def LOGWARN(self, text):
|
|
|
+ if self.log_lvl <= 2:
|
|
|
+ self._log("WARN", text)
|
|
|
+
|
|
|
+ def LOGERR(self, text):
|
|
|
+ if self.log_lvl <= 3:
|
|
|
+ self._log("ERROR", text)
|
|
|
+
|
|
|
+
|
|
|
+# ================== 全局实例 ==================
|
|
|
+g_logger = Logger(
|
|
|
+ module_name="MyModule",
|
|
|
+ log_path="./logs",
|
|
|
+ max_log_size=50*1024*1024, # 2 MB
|
|
|
+ max_log_files=5,
|
|
|
+ log_lvl=1
|
|
|
+)
|
|
|
+
|
|
|
+# ========== 使用示例 ==========
|
|
|
+if __name__ == "__main__":
|
|
|
+ g_logger.LOGINFO("启动服务成功")
|
|
|
+ g_logger.LOGDBG("这是调试信息")
|
|
|
+ g_logger.LOGWARN("这是警告")
|
|
|
+ g_logger.LOGERR("这是错误信息")
|