Linux的tail/tailf命令使用了内核提供的inotify功能,下面的Python例子也使用inotify实现比tail/tailf更强的监控文件功能。
watchfile.py
#!/usr/bin/python import sys, os, pyinotify notifier = None monfile = None lastsize = 0 wm = None wd = 0 def roll_file(filename): global lastsize fd = os.open(filename, os.O_RDONLY) try: newsize = os.fstat(fd).st_size if newsize <= lastsize: return os.lseek(fd, lastsize, os.SEEK_SET) while True: data = os.read(fd, 4096) if not data: break sys.stdout.write(data) sys.stdout.flush() pos = os.lseek(fd, 0, os.SEEK_CUR) lastsize = pos if pos != lastsize else newsize finally: os.close(fd) class EventHandler(pyinotify.ProcessEvent): def process_IN_CREATE(self, event): if monfile == event.pathname: global wd wd = wm.add_watch(monfile, pyinotify.IN_MODIFY).values()[0] roll_file(monfile) def process_IN_DELETE(self, event): global wd, lastsize if monfile == event.pathname: if wd > 0: try: wm.rm_watch(wd, quiet=False) except pyinotify.WatchManagerError: pass wd = 0 lastsize = 0 def process_IN_MOVED_FROM(self, event): self.process_IN_DELETE(event) def process_IN_MOVED_TO(self, event): self.process_IN_DELETE(event) self.process_IN_CREATE(event) def process_IN_MODIFY(self, event): roll_file(monfile) def main(): global notifier, lastsize, wm, wd, monfile monfile = os.path.abspath(sys.argv[1]) print "path={0}".format(monfile) lastsize = os.stat(monfile).st_size wm = pyinotify.WatchManager() notifier = pyinotify.Notifier(wm, EventHandler()) wd = wm.add_watch(monfile, pyinotify.IN_MODIFY).values()[0] wm.add_watch(os.path.dirname(monfile), pyinotify.IN_DELETE | pyinotify.IN_CREATE | pyinotify.IN_MOVED_FROM | pyinotify.IN_MOVED_TO) print "watching {0} ...".format(monfile) while True: notifier.process_events() if notifier.check_events(): notifier.read_events() if __name__ == "__main__": try: main() finally: if notifier: notifier.stop()
使用方法:
./watchfile.py ~/test.log
被监控的文件做改名、删除、创建的操作都可以继续监控。