import os
import logging
import datetime
from logging.handlers import RotatingFileHandler
from watchdog.observers import Observer
from watchdog.events import FileSystemEventHandler
import time
class UserLog(object):
def __init__(self):
self.logger = logging.getLogger(__name__)
self.logger.handlers = [] # 清空handlers,防止重复添加
self.logger.setLevel(logging.DEBUG) # 测试环境
# 创建日志文件夹
base_dir = os.path.dirname(os.path.abspath(__file__))
log_dir = os.path.join(base_dir, "logs")
if not os.path.exists(log_dir):
os.makedirs(log_dir)
# 日志文件名
log_file = datetime.datetime.now().strftime("%Y-%m-%d") + ".log"
self.log_name = os.path.join(log_dir, log_file)
# 文件输出日志
self.file_handle = logging.handlers.RotatingFileHandler(self.log_name, maxBytes=10000, backupCount=5)
self.file_handle.setLevel(logging.ERROR)
# 日志格式
formatter = logging.Formatter(
'%(asctime)s %(filename)s --> %(funcName)s %(levelno)s: %(levelname)s -----> %(message)s')
self.file_handle.setFormatter(formatter)
self.logger.addHandler(self.file_handle)
# 启动日志文件变化监控
self.start_file_monitor()
def start_file_monitor(self):
observer = Observer()
#事件处理程序与监控路径关联起来,
observer.schedule(LogFileHandler(self.log_name), os.path.dirname(self.log_name))
#启动观察者
observer.start()
print(f"Started monitoring {self.log_name} for changes...")
def get_log(self):
return self.logger
def close_handle(self):
self.logger.removeHandler(self.file_handle)
self.file_handle.close()
class LogFileHandler(FileSystemEventHandler):
def __init__(self, log_file):
self.log_file = log_file
self.error_lines = set() # 用于存储已经打印过的包含"ERROR"的行
def on_modified(self, event):
if event.src_path == self.log_file and event.event_type == 'modified':
with open(self.log_file, 'r') as f:
lines = f.readlines()
for line in lines:
if "ERROR" in line and line not in self.error_lines: # 检查是否已经打印过
print(f"Error found in log: {line.strip()}")
self.error_lines.add(line) # 将该行添加到已打印集合
# 示例用法
if __name__ == "__main__":
# 创建监控程序实例
# 创建日志实例
user_log = UserLog()
# 获取日志记录器
logger = user_log.get_log()
# 模拟写入一些日志
logger.debug("This is a debug message.")
logger.info("This is an info message.")
logger.warning("This is a warning message.")
logger.error("This is a message.")
logger.critical("This is a critical message.")
# 模拟运行时持续写入日志
try:
while True:
logger.info("Still running...")
time.sleep(1)
except KeyboardInterrupt:
print("Stopping the program...")
# 关闭日志处理器
user_log.close_handle()
UserLog
类:__init__
方法:- 初始化日志记录器,设置级别为
DEBUG
。 - 创建日志文件夹,如果不存在则创建。
- 生成当前日期的日志文件名,并设置文件处理器的相关参数,如文件路径、大小限制、备份数量和日志级别。
- 设置日志格式,并将文件处理器添加到日志记录器。
- 启动日志文件变化的监控。
- 初始化日志记录器,设置级别为
start_file_monitor
方法:创建观察者,将自定义的事件处理程序与日志文件所在的目录关联,并启动观察者。get_log
方法:返回日志记录器,供外部使用。close_handle
方法:从日志记录器中移除文件处理器,并关闭文件处理器。
LogFileHandler
类:- 继承自
FileSystemEventHandler
,用于处理日志文件的修改事件。 - 在
on_modified
方法中,当监测到日志文件被修改时,读取文件内容,查找包含 “ERROR” 且未被处理过的行,并打印出来,同时将其添加到已处理的集合中。
- 继承自
示例用法部分:
- 创建
UserLog
对象,并获取其日志记录器。 - 模拟写入不同级别的日志消息。
- 一个无限循环模拟持续运行并写入日志。
- 捕获
KeyboardInterrupt
异常,处理程序停止的情况。 - 最后关闭日志处理器。
- 创建