python:连续读取文件,即使它已经被日志旋转
我有一个简单的python脚本,在这里我可以连续读取日志文件(与python:连续读取文件,即使它已经被日志旋转,python,file,Python,File,我有一个简单的python脚本,在这里我可以连续读取日志文件(与tail-f相同) 在日志文件被logrotate旋转后,如何确保我仍然可以读取日志文件 i、 e.我需要做与tail-F相同的事情 我使用的是python2.7您可以跟踪文件中的位置,并在需要阅读时重新打开它。当日志文件旋转时,您会注意到文件变小了,并且由于重新打开,您也会处理任何取消链接的操作 import time cur = 0 while True: try: with open('myfile'
tail-f
相同)
在日志文件被logrotate旋转后,如何确保我仍然可以读取日志文件
i、 e.我需要做与tail-F
相同的事情
我使用的是
python2.7
您可以跟踪文件中的位置,并在需要阅读时重新打开它。当日志文件旋转时,您会注意到文件变小了,并且由于重新打开,您也会处理任何取消链接的操作
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)
导入时间
cur=0
尽管如此:
尝试:
将open('myfile')作为f:
f、 搜索(0,2)
如果f.tell()
此示例隐藏了诸如“找不到文件”之类的错误,因为我不确定logrotate的详细信息,例如文件不可用的小时间段。只要您只计划在Unix上执行此操作,最可靠的方法可能是进行检查,以便打开的文件仍然与名称相同,当情况不再如此时,重新打开它。您可以在
st_ino
字段中从os.stat
和os.fstat
获取文件的i号
它可能是这样的:
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上是否有效,但既然您是从
尾部
的角度讲的,我猜这不是问题。:) 多亏了@tdelaney和@Dolda2000的回答,我最终得到了以下结果。它应该可以在Linux和Windows上工作,还可以处理logrotate的copyruncate
或create
选项(分别是复制然后将大小截断为0,移动然后重新创建文件)
使用
copyruncate
选项时的一个限制是,如果在睡眠时将行追加到文件中,并且在唤醒之前发生旋转,最后的行将“丢失”(它们仍将位于现在的“旧”日志文件中,但我看不到一个合适的方法“跟随”该文件完成读取)。此限制与“移动并创建”create
选项无关,因为f
描述符仍将指向重命名的文件,因此在关闭并再次打开描述符之前,最后一行将被读取。可能不是重复的,但肯定是相关的:有一个配方可以做到这一点。不过我自己还没试过。非常感谢。不过,我想知道是否有更好/更优雅的解决方案。例如,有没有办法检查我的文件描述符f
是否仍然指向文件file.log
?我猜想,在文件被日志旋转之后,文件描述符仍然会指向旧文件,而不是新的文件。log
这对于文件操作来说是相当优雅的。问题是,如果文件保持打开状态,其文件描述符将继续指向已旋转的文件,而不是新文件。如果不重新检查原始文件名,就无法判断它是否已过期。另一种方法是使用inotify,它可以让您随时了解文件操作。这更复杂,但也是一个很好的方法。要不要详细说明一下否决票:)?我很乐意更新答案。
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)
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)