在监控系统中要做一个监控文件的功能:实时监控日志文件,若发生变化则使用websocket通知前端(web页面),并返回新增的日志记录。
出事代码是这样的:
/**
* 文件监控处理
*
* [@param](/user/param) socket
*/
function monitor_handler(socket){
var files_to_monitor =config.files_to_monitor;
for(var key in files_to_monitor){
console.log('开始:'+key);
fs.watchFile(files_to_monitor[key].file_path , function(curr, prev){
console.log('触发:'+key + ',处理文件'+files_to_monitor[key].file_path);
if (curr.mtime.getTime() !== prev.mtime.getTime()) {
notify_client(key, files_to_monitor[key].file_path, curr, socket);
}
});
}
}
乍看上去,代码很简单,config.files_to_monitor的结构是这样的:
files_to_monitor : {
'data' : {
label : '日志文件1',
file_path : '/home/tmp2/data',
},
'data2' : {
label : '日志文件2',
file_path : '/home/tmp2/data2',
},
'data3' : {
label : '日志文件3',
file_path : '/home/tmp2/data3',
},
}
也就是需要监控配置的每个文件,然后在它发生变化后通过指定的key来emit前端websocket事件。所以fs.watchFile的回调会调用这个key,如果说到这里你能明白的话,那就不用往下看了。
按照上述代码,测试时,我分别改变三个文件,然后观察websocket的debug信息,结果是这样的:
root[@sumory-laptop](/user/sumory-laptop):/home/tmp2# echo data '模拟数据' > data
root[@sumory-laptop](/user/sumory-laptop):/home/tmp2# echo data '模拟数据' > data2
root[@sumory-laptop](/user/sumory-laptop):/home/tmp2# echo data '模拟数据' > data3
触发:data3,处理文件/home/tmp2/data3
debug - websocket writing 5:::{"name":"data3","args":[{"updatetime":"2012-3-25 19:12:04","content":"data fdsffsfdsfsfdfsfdsfsdfdsfsfds\n"}]}
触发:data3,处理文件/home/tmp2/data3
debug - websocket writing 5:::{"name":"data3","args":[{"updatetime":"2012-3-25 19:12:07","content":"data fdsffsfdsfsfdfsfdsfsdfdsfsfds\n"}]}
触发:data3,处理文件/home/tmp2/data3
debug - websocket writing 5:::{"name":"data3","args":[{"updatetime":"2012-3-25 19:12:10","content":"data 模拟数据\n"}]}
好吧,2B了,永远只会触发data3:
- 起初还以为代码有问题,挨个字母检查,没问题啊;
- 仔细查看nodejs的fs部分文档,函数也没有用错;
- 增加一配置项,发现只会调用最后一项配置,也就是for循环的最后一项。
恍然大悟,fs.watchFile监控并触发事件不是通过回调的嘛,回调在声明时不会调用,只有文件发生变化是才会调用,这是的key不是已经循环到最后了,当然也就会永远只触发最后一个(好吧,就这么一个坑,我就粪不顾身地随便跳进去了....)。
改写后正确的结果:
/**
* 文件监控处理
*
* [@param](/user/param) socket
*/
function monitor_handler(socket){
var files_to_monitor =config.files_to_monitor;
for(var key in files_to_monitor){
console.log('开始:'+key);
watch_file(key, files_to_monitor[key].file_path, socket);
}
}
function watch_file(key, full_file_path, socket){
fs.watchFile(full_file_path, function(curr, prev){
console.log('触发:'+key + ',处理文件'+full_file_path);
if (curr.mtime.getTime() !== prev.mtime.getTime()) {
notify_client(key, full_file_path, curr, socket);
}
});
}
恶心得蛋都碎了..以后还是留点神吧...