文章目录
当我的日志文件第10086次被覆盖时…
“谢特!谁动了我的配置文件?!” —— 这大概是我职业生涯中喊过最多次的台词。曾经为了监控日志变化,我写过这样的史诗级烂代码:
import time
while True:
with open('app.log') as f:
new_lines = f.readlines()[last_line:]
if new_lines:
process(new_lines) # 处理新日志
last_line += len(new_lines)
time.sleep(5) # 每5秒轮询一次(CPU在燃烧!)
直到某天服务器的风扇开始演奏《野蜂飞舞》…(别笑!我知道你干过同样的事)
Watchdog出手!三步终结轮询时代
🚀 1. 安装就是一行的事(pip大法好!)
pip install watchdog
# 不用纠结版本,最新版永远是你的好朋友
🚀 2. 基础监控脚本(10行搞定奇迹)
from watchdog.observers import Observer
from watchdog.events import FileSystemEventHandler
class MyHandler(FileSystemEventHandler):
def on_modified(self, event):
if not event.is_directory: # 过滤文件夹噪声
print(f"🔥 文件被修改了!: {event.src_path}")
observer = Observer()
observer.schedule(MyHandler(), path='./监控目录', recursive=True)
observer.start()
try:
while True:
time.sleep(1) # 优雅睡觉不占CPU
except KeyboardInterrupt:
observer.stop()
observer.join()
🚀 3. 进阶玩法:事件延迟聚合(防手抖神器!)
from watchdog.events import FileSystemEventHandler
from watchdog.utils.delayed_queue import DelayedQueue
class SmartHandler(FileSystemEventHandler):
def __init__(self):
self.queue = DelayedQueue(delay=2.0) # 2秒延迟聚合
def on_modified(self, event):
self.queue.put((event, lambda: print(f"📦 批量处理: {event.src_path}")))
真实场景暴打面试题案例
▍场景1:自动编译Less/Sass
def on_modified(event):
if event.src_path.endswith('.scss'):
os.system(f"sass {event.src_path} {event.src_path.replace('.scss','.css')}")
print("🎨 CSS自动生成完毕!")
▍场景2:深度学习数据集监听
def on_created(event):
if '.jpg' in event.src_path:
add_to_training_queue(event.src_path) # 加入训练队列
print(f"🦾 新图片已投喂给AI: {os.path.basename(event.src_path)}")
▍场景3:配置文件热更新(不用重启服务!)
def on_modified(event):
if 'config.yaml' in event.src_path:
global CONFIG
CONFIG = load_config() # 重新加载配置
print("⚡ 配置热更新成功!服务无感切换~")
避坑指南(血泪换的经验!)
-
路径陷阱 👉
event.src_path
在Windows可能是C:\\dir
,Linux是/home/dir
解决方案:path = os.path.normpath(event.src_path)
统一格式化 -
事件风暴 💥 保存大文件可能触发数十次modified事件
解决方案:用前文的DelayedQueue或debounce
函数(代码在下面👇) -
权限巨坑 🔑 监控
/etc
等系统目录?记得sudo
启动脚本!(不然等着收PermissionError大礼包)
# 事件防抖装饰器(直接抄!)
def debounce(wait_time):
def decorator(func):
last_call = 0
def wrapped(*args, **kwargs):
nonlocal last_call
now = time.time()
if now - last_call > wait_time:
func(*args, **kwargs)
last_call = now
return wrapped
return decorator
# 使用示例
class SafeHandler(FileSystemEventHandler):
@debounce(1.0) # 1秒内只触发一次
def on_modified(self, event):
print("💫 优雅处理高频事件")
冷知识:监控原理大揭秘
你以为Watchdog在用黑魔法?其实核心就两个东西:
- inotify (Linux内核级监控) - 连文件被
rm
都能抓到!(没错,比你的眼睛还快) - kqueue (MacOS高效事件通知) - 苹果党福音
- ReadDirectoryChangesW (Windows API) - 微软的祖传手艺
实测数据:同时监控10万个文件,Watchdog内存占用仅50MB左右(而你写轮询?内存早爆了!)
彩蛋:监控网络目录?当然可以!
# 挂载WebDAV/NFS后直接监控
observer.schedule(
handler,
path="/mnt/nas_project",
recursive=True
)
⚠️ 但要注意网络延迟可能造成事件丢失(重要操作记得加确认机制)
最后说点人话
自从用了Watchdog:
- 再也不用写
while sleep
轮询了(CPU感谢你!) - 配置文件改了秒生效(运维同事给你磕头)
- 新数据自动触发训练(老板以为你24小时加班)
现在我的监控脚本安静如猫,只有文件变动时才会"喵"一声告诉我——这才是程序员该有的优雅啊!
Github传送门:https://github.com/gorakhargosh/watchdog (记得给作者点星⭐,救你于水火的大佬值得!)
# 今日份救命代码,存为watchdog_demo.py直接开跑!
# 从此和文件监控焦虑说拜拜 👋