我有一个简单的python脚本,我连续读取logfile(与tail -f
相同)
while True:
line = f.readline()
if line:
print line,
else:
time.sleep(0.1)
如何通过logrotate旋转后仍然可以确保我仍然可以读取日志文件?
即。我需要做tail -F
会做的事情。
我正在使用python 2.7
答案 0 :(得分:12)
只要您计划在Unix上执行此操作,最可靠的方法是检查以便打开的文件仍然引用与名称相同的i-node,并在不再使用时重新打开它案子。您可以在os.stat
字段中的os.fstat
和st_ino
获取该文件的i-number。
看起来像这样:
import os, sys, time
name = "logfile"
current = open(name, "r")
curino = os.fstat(current.fileno()).st_ino
while True:
while True:
buf = current.read(1024)
if buf == "":
break
sys.stdout.write(buf)
try:
if os.stat(name).st_ino != curino:
new = open(name, "r")
current.close()
current = new
curino = os.fstat(current.fileno()).st_ino
continue
except IOError:
pass
time.sleep(1)
我怀疑这可以在Windows上运行,但是由于您在tail
方面发言,我猜这不是问题。 :)
答案 1 :(得分:4)
您可以通过跟踪文件中的位置并在想要阅读时重新打开来实现。当日志文件旋转时,您会注意到该文件较小,并且自重新打开后,您也可以处理任何取消链接。
import time
cur = 0
while True:
try:
with open('myfile') as f:
f.seek(0,2)
if f.tell() < cur:
f.seek(0,0)
else:
f.seek(cur,0)
for line in f:
print line.strip()
cur = f.tell()
except IOError, e:
pass
time.sleep(1)
此示例隐藏了未找到文件等错误,因为我不确定logrotate详细信息,例如文件不可用的小时间段。
答案 2 :(得分:1)
感谢@tdelaney和@ Dolda2000的答案,我最终得到了以下内容。它应该适用于Linux和Windows,并且还可以处理logrotate的copytruncate
或create
选项(分别复制然后将大小截断为0并移动然后重新创建文件)。
file_name = 'my_log_file'
seek_end = True
while True: # handle moved/truncated files by allowing to reopen
with open(file_name) as f:
if seek_end: # reopened files must not seek end
f.seek(0, 2)
while True: # line reading loop
line = f.readline()
if not line:
try:
if f.tell() > os.path.getsize(file_name):
# rotation occurred (copytruncate/create)
f.close()
seek_end = False
break
except FileNotFoundError:
# rotation occurred but new file still not created
pass # wait 1 second and retry
time.sleep(1)
do_stuff_with(line)
使用copytruncate
选项时的限制是,如果在时间休眠时将行附加到文件,并且在唤醒之前发生旋转,则最后一行将是&#34 ;丢失&#34; (他们仍然会在现在的#34;旧的#34;日志文件中,但我看不到一个体面的方式来跟随&#34;该文件完成阅读它。此限制与&#34;移动和创建&#34;无关。 create
选项因为f
描述符仍将指向重命名的文件,因此在描述符关闭并再次打开之前将读取最后一行。