nv-file-watch
v1.0.7
Published
基于 `nd-file-notify` 的高性能文件监控服务,带 Web UI 和 SSE 实时推送。
Downloads
614
Readme
nv-file-watch
基于 nd-file-notify 的高性能文件监控服务,带 Web UI 和 SSE 实时推送。
✨ 功能特性
- 🚀 高性能监控 - 基于 Linux fanotify API,零轮询开销
- 🔄 重命名检测 - 内核 5.17+ 支持原子重命名事件(包含源和目标路径)
- 🔗 符号链接识别 - 自动检测符号链接并解析目标路径
- 🌐 Web UI - 实时事件可视化,分类显示
- 📡 SSE 推送 - 服务器发送事件(Server-Sent Events)实时通知
- 🔌 Nginx 集成 - 支持 Unix socket,轻松集成到 Nginx
- 🔐 HTTPS 支持 - 可配置 SSL/TLS
- ⚡ 内核兼容 - 自动降级支持低版本内核
- 🎯 智能过滤 - 嵌套删除过滤,只报告顶层事件
📋 系统要求
- 操作系统: Linux
- 内核版本:
- 推荐: 5.17+ (完整 FAN_RENAME 支持)
- 最低: 5.9+ (FAN_REPORT_DFID_NAME 支持)
- 兼容性: < 5.17 自动降级为 moved_from/moved_to 事件
- 权限: root 或 CAP_SYS_ADMIN
- Node.js: 14+ (需要 N-API 支持)
📦 安装
npm install nv-file-watch🚀 快速开始
基本用法(控制台输出)
const createWatch = require("nv-file-watch");
// 监控目录,输出到控制台
const srv = await createWatch("/path/to/watch");启用 Web UI
const createWatch = require("nv-file-watch");
// 监控目录,启动 Web UI 在 http://localhost:3000
const srv = await createWatch("/path/to/watch", "http://127.0.0.1:3000");
// 访问 http://127.0.0.1:3000 查看实时事件自定义回调
const createWatch = require("nv-file-watch");
const srv = await createWatch(
"/home/user",
undefined, // 不启动 SSE 服务
(ftype, event_name, path, path2) => {
if (event_name === "renamed") {
// 内核 5.17+ 支持
console.log(`[RENAME] ${ftype}: ${path} -> ${path2}`);
} else if (event_name === "moved_from") {
// 内核 < 5.17 降级
console.log(`[MOVE FROM] ${ftype}: ${path}`);
} else if (event_name === "moved_to") {
// 内核 < 5.17 降级
console.log(`[MOVE TO] ${ftype}: ${path}`);
} else if (ftype === "link" && event_name === "created") {
console.log(`[SYMLINK] ${path} -> ${path2}`);
} else {
console.log(`[${event_name.toUpperCase()}] ${ftype}: ${path}`);
}
}
);🔧 API 文档
主函数
async function createWatch(
watch_dir?: string, // 监控目录,默认 "/"
listen_on?: string, // SSE 服务地址,undefined 则不启动
callback?: Function, // 事件回调
chown_to_user?: string, // Unix socket 所有者
key_buf?: Buffer, // HTTPS 私钥
cert_buf?: Buffer // HTTPS 证书
): Promise<Srv>参数说明:
- watch_dir: 要监控的目录路径(绝对或相对路径)
- listen_on:
- HTTP/HTTPS:
"http://127.0.0.1:3000"或"https://0.0.0.0:3443" - Unix socket:
"___socket_name___"(配合 Nginx) undefined: 不启动 SSE 服务
- HTTP/HTTPS:
- callback: 事件回调函数
(ftype, event_name, path, path2) => void- ftype:
"dire"|"file"|"link" - event_name:
"created"|"deleted"|"modified"|"renamed"|"moved_from"|"moved_to"|"attr" - path: 文件路径(renamed 时为源路径,link 时为链接路径)
- path2: 第二路径(renamed 时为目标路径,link 时为目标路径)
- ftype:
- chown_to_user: Unix socket 文件所有者,如
"www-data"(仅 Unix socket 有效) - key_buf: HTTPS 私钥 Buffer
- cert_buf: HTTPS 证书 Buffer
返回值:
interface Srv {
mon: {
start(): void;
stop(): void;
add(path: string): boolean;
del(path: string): boolean;
has(path: string): boolean;
list(): string[];
};
sse: any; // SSE 服务器实例(如果启用)
}Nginx 配置生成器
const { creat_ngx_srv } = require("nv-file-watch");
const config = creat_ngx_srv(
"/var/www", // 监控目录
"/opt/app", // 工作目录(socket 位置)
8847 // 端口
);
console.log(config.ngx); // Nginx 配置
console.log(config.code); // Node.js 启动代码🌐 Web UI 使用
启动服务
const srv = await require("nv-file-watch")(
"/path/to/watch",
"http://0.0.0.0:3000" // 监听所有网卡
);访问界面
打开浏览器访问 http://服务器IP:3000
功能:
- 📊 实时事件统计
- 📝 按类型分类的事件日志
- 🎨 事件类型颜色编码:
- 🟢 绿色:创建
- 🟡 黄色:修改
- 🔴 红色:删除
- 🔵 青色:重命名
- 🟠 橙色:移出 (moved_from)
- 🟢 青绿:移入 (moved_to)
- 🟣 紫色:属性
- 🔗 符号链接显示目标路径
- 🔄 重命名显示源和目标路径
🔌 Nginx 集成
1. 生成配置
const { creat_ngx_srv } = require("nv-file-watch");
const config = creat_ngx_srv("/var/www", "/opt/app", 8847);
// 保存配置
const fs = require("fs");
fs.writeFileSync("/etc/nginx/conf.d/filewatch.conf", config.ngx);
fs.writeFileSync("/opt/app/start.js", config.code);2. 生成的 Nginx 配置示例
server {
listen 8847;
# 根路径返回 HTML
location = / {
proxy_pass http://unix:/opt/app/___nv_file_watch___:/NvSSEClient.html;
}
# SSE 和静态资源
location / {
proxy_pass http://unix:/opt/app/___nv_file_watch___;
}
}3. 启动服务
# 启动 Node.js 服务(使用 www-data 用户)
sudo -u www-data node /opt/app/start.js
# 重载 Nginx
sudo nginx -s reload
# 访问 http://your-server:88474. 使用 systemd 管理
# /etc/systemd/system/filewatch.service
[Unit]
Description=File Watch Service
After=network.target
[Service]
Type=simple
User=www-data
WorkingDirectory=/opt/app
ExecStart=/usr/bin/node /opt/app/start.js
Restart=always
RestartSec=10
[Install]
WantedBy=multi-user.targetsudo systemctl enable filewatch
sudo systemctl start filewatch
sudo systemctl status filewatch📝 事件类型说明
内核 5.17+ (推荐)
| 事件 | 说明 | ftype | path | path2 |
|------|------|-------|------|-------|
| created | 文件/目录创建 | file/dire | 新建路径 | - |
| created | 符号链接创建 | link | 链接路径 | 目标路径 |
| deleted | 文件/目录删除 | file/dire | 删除路径 | - |
| modified | 文件/目录修改 | file/dire | 修改路径 | - |
| renamed | 文件/目录重命名 | file/dire | 源路径 | 目标路径 |
| attr | 属性变化 | file/dire | 路径 | - |
内核 5.9-5.16 (降级模式)
重命名操作会产生两个独立事件:
| 事件 | 说明 | ftype | path | path2 |
|------|------|-------|------|-------|
| moved_from | 从原位置移出 | file/dire | 源路径 | undefined |
| moved_to | 移入新位置 | file/dire | 目标路径 | undefined |
注意: 低版本内核无法将 moved_from 和 moved_to 关联起来,需要在应用层自行匹配。
🔬 高级特性
1. 嵌套删除过滤
删除包含文件的目录时,只报告顶层目录删除事件,不报告内部文件/子目录的删除:
// 删除 /data/dir1 (包含 file1.txt 和 subdir/)
// 只产生一个事件:
// { ftype: 'dire', event_name: 'deleted', path: '/data/dir1' }2. LRU 路径缓存
自动缓存文件句柄到路径的映射,显著提升性能(10-100倍加速):
- 缓存大小: 65536 entries
- 自动过期: ESTALE 错误时清理
- 级联清理: 父目录删除时清理子项
3. 符号链接检测
创建符号链接时自动检测并解析目标路径:
// ln -s /target/path /link/path
// 产生事件:
// { ftype: 'link', event_name: 'created', path: '/link/path', target: '/absolute/target/path' }4. 动态监控管理
const srv = await createWatch("/", "http://127.0.0.1:3000");
// 添加监控目录
srv.mon.add("/new/path");
// 移除监控
srv.mon.del("/old/path");
// 检查是否监控
const watching = srv.mon.has("/some/path");
// 列出所有监控目录
const dirs = srv.mon.list();
// 停止监控
srv.mon.stop();
// 重启监控
srv.mon.start();🛡️ 安全考虑
- 权限要求: 需要 root 或 CAP_SYS_ADMIN
- 性能影响: fanotify 在高负载下可能影响系统性能(已优化,使用 LRU 缓存)
- 路径泄露: Web UI 会暴露文件系统路径,建议使用 Unix socket + Nginx 并配置访问控制
- 资源限制: 内核对 fanotify 实例数和标记数有限制
🐛 故障排查
权限错误
Error: fanotify_init failed: Operation not permitted解决: 使用 sudo 运行或添加 CAP_SYS_ADMIN 能力
sudo node app.js
# 或
sudo setcap 'cap_sys_admin+ep' $(which node)内核版本不支持
Error: FAN_REPORT_DFID_NAME not supported解决: 升级内核到 5.9+ 或使用传统的 inotify 方案
事件丢失
检查内核日志:
dmesg | grep fanotify增加内核限制:
# /etc/sysctl.conf
fs.fanotify.max_user_marks = 1048576
fs.fanotify.max_user_groups = 128
sudo sysctl -pWeb UI 无法访问
检查防火墙:
sudo ufw allow 3000/tcp
# 或
sudo firewall-cmd --add-port=3000/tcp --permanent
sudo firewall-cmd --reload📚 相关项目
- nd-file-notify - 核心 fanotify 监控模块
- nv-srv-nd-http-util - SSE 服务器工具
📄 License
ANY
