Python - 尾随日志文件 - sleep()与inotify?

时间:2013-03-29 08:04:46

标签: python file-io tail

我正在编写一个需要tail -f日志文件的Python脚本。

操作系统是RHEL,运行Linux 2.6.18。

我认为通常的方法是使用带睡眠的无限循环来持续轮询文件。

但是,既然我们在Linux上,我想我也可以使用像pyinotify(https://github.com/seb-m/pyinotify)或看门狗(https://github.com/gorakhargosh/watchdog)这样的东西?

这有什么优点/缺点?

我听说使用sleep(),你可以错过事件,如果文件快速增长 - 可能吗?我认为GNU尾部无论如何都会使用睡眠?

干杯, 维克多

1 个答案:

答案 0 :(得分:5)

最干净的解决方案是以多种方式进行inotify - 毕竟这或多或少完全符合它的目的。如果日志文件变化非常快,那么您可能会冒险被几乎不断地唤醒,这不一定特别有效 - 但是,您可以通过在inotify文件句柄返回事件后添加自己的短暂延迟来缓解此问题。在实践中,我怀疑这在大多数系统上都是一个问题,但我认为值得一提,以防你的系统CPU资源非常紧张。

我无法看到sleep()方法如何错过文件更新,除非文件被截断或旋转(即重命名并创建了同名的另一个文件)。这些是棘手的情况,无论你做什么都可以处理,你可以使用技巧,例如定期按名称重新打开文件以检查旋转。阅读tail手册页,因为它处理了许多这样的情况,特别是对于日志文件来说它们很常见(日志轮换被广泛认为是一种很好的做法)。

sleep()的缺点当然是你最终会在读取之间加上延迟,并且即使它没有改变,你也有不断唤醒和轮询文件的开销。但是,如果你这样做,比如每秒一次,那么在大多数系统上开销可能都不明显。

我认为inotify是最好的选择,除非你想保持兼容,在这种情况下使用sleep()的简单回退仍然是非常合理的。

修改

我刚刚意识到我忘了提及 - 检查要重命名的文件的一种简单方法是在打开的文件句柄上执行os.fstat(fd.fileno()),在打开的文件名上执行os.stat()并比较结果。如果os.stat()失败,则错误将告诉您文件是否已被删除,如果没有,则比较st_ino(inode编号)字段将告诉您文件是否已被删除然后替换为新的同名。

检测截断更难 - 有效的读取指针保持在文件中的相同偏移量,读取将不返回任何内容,直到文件内容大小恢复到原来的位置 - 然后文件将从该点正常读取。如果经常调用os.stat(),您可以检查文件大小是否倒退 - 或者您可以使用fd.tell()在文件中记录当前位置,然后执行显式搜索到文件末尾并调用再次fd.tell()。如果该值较低,则该文件在您下面被截断。这是一个安全的操作,只要您保持原始文件位置,因为您可以在检查后始终寻找它。

或者,如果您仍在使用inotify,则只需查看父目录即可进行更改。

请注意,文件可以被截断为非零大小,但我怀疑这可能发生在日志文件中 - 常见情况将被删除和替换,或截断为零。此外,我不知道你是如何检测文件被截断的情况,然后立即填充回到当前位置之外,除了记住最近的N个字符并比较它们,但这是一个非常难以理解的事情。做。我认为inotify会告诉你该文件已被修改过。