如何在Python中定尾日志文件?

我想在Python中输出tail -F或类似的东西,而不用阻塞或locking。 我在这里发现了一些非常古老的代码,但是我认为现在必须有一个更好的方法或者一个库去做同样的事情。 任何人都知道吗?

理想情况下,我会有像tail.getNewData() ,我可以每次需要更多的数据时调用。

不阻塞

如果你在linux上(因为windows不支持调用select文件),你可以使用subprocess模块和select模块。

 import time import subprocess import select f = subprocess.Popen(['tail','-F',filename],\ stdout=subprocess.PIPE,stderr=subprocess.PIPE) p = select.poll() p.register(f.stdout) while True: if p.poll(1): print f.stdout.readline() time.sleep(1) 

这将轮询输出pipe道以获取新数据,并在可用时打印它。 通常print f.stdout.readline() time.sleep(1)print f.stdout.readline()将被replace为有用的代码。

闭塞

您可以使用subprocess模块,而无需额外的select模块调用。

 import subprocess f = subprocess.Popen(['tail','-F',filename],\ stdout=subprocess.PIPE,stderr=subprocess.PIPE) while True: line = f.stdout.readline() print line 

这也会在添加新的行时打印出新的行,但是在尾部程序closures之前它会被阻塞,可能会使用f.kill()

使用sh模块 (pip install sh):

 from sh import tail # runs forever for line in tail("-f", "/var/log/some_log_file.log", _iter=True): print(line) 

[更新]

由于使用_iter = True的_iter是一个生成器,所以您可以:

 import sh tail = sh.tail("-f", "/var/log/some_log_file.log", _iter=True) 

那么你可以使用“getNewData”

 new_data = tail.next() 

请注意,如果尾部缓冲区为空,它将阻塞,直到有更多的数据(从你的问题是不清楚你想要在这种情况下做什么)。

[更新]

如果你用-Freplace-f,这会起作用,但是在Python中它会被locking。 如果可能的话,我会更感兴趣的是可以调用一个函数来获取新数据。 – Eli

一个容器生成器将尾部调用放在True循环中,捕捉最终的I / Oexception将具有与-F几乎相同的效果。

 def tail_F(some_file): while True: try: for line in sh.tail("-f", some_file, _iter=True): yield line except sh.ErrorReturnCode_1: yield None 

如果文件变得不可访问,生成器将返回None。 但是,如果文件是可访问的,它仍会阻塞,直到有新的数据。 在这种情况下,我还不清楚你想做什么。

雷蒙德·赫廷格的做法似乎相当不错:

 def tail_F(some_file): first_call = True while True: try: with open(some_file) as input: if first_call: input.seek(0, 2) first_call = False latest_data = input.read() while True: if '\n' not in latest_data: latest_data += input.read() if '\n' not in latest_data: yield '' if not os.path.isfile(some_file): break continue latest_lines = latest_data.split('\n') if latest_data[-1] != '\n': latest_data = latest_lines[-1] else: latest_data = input.read() for line in latest_lines[:-1]: yield line + '\n' except IOError: yield '' 

如果文件变得不可访问或者没有新的数据,这个生成器将返回“'。

[更新]

第二个到最后一个答案围绕文件的顶部,似乎每当数据用完。 – Eli

我认为每当尾进程结束时,第二行将输出最后十行,每当有I / O错误时使用-f 。 在unix-like环境中,我可以想到的大多数情况下, tail --follow --retry行为与此tail --follow --retry

也许如果你更新你的问题来解释你真正的目标是什么(你想模仿尾巴的原因),你会得到一个更好的答案。

最后的答案实际上并不遵循尾部,只是读取运行时可用的内容。 – Eli

当然,tail会默认显示最后10行……您可以使用file.seek将文件指针定位在文件末尾,我将为读者留下一个适当的实现。

恕我直言,file.read()方法比基于subprocess的解决scheme更加优雅。

实际上,如果read返回0,那么实际上只能读取文件并重试( sleep )。在各种平台上的tail实用程序使用特定于平台的技巧(例如,BSD上的kqueue )有效地尾随一个文件,而不需要sleep

因此,纯粹用Python实现一个好的tail -f可能不是一个好主意,因为你必须使用最小公分母实现(而不是采用特定于平台的黑客)。 使用一个简单的subprocess进程来打开tail -f并遍历一个单独的线程中的行,你可以很容易地在Python中实现一个非阻塞的tail操作。

示例实现:

 import threading, Queue, subprocess tailq = Queue.Queue(maxsize=10) # buffer at most 100 lines def tail_forever(fn): p = subprocess.Popen(["tail", "-f", fn], stdout=subprocess.PIPE) while 1: line = p.stdout.readline() tailq.put(line) if not line: break threading.Thread(target=tail_forever, args=(fn,)).start() print tailq.get() # blocks print tailq.get_nowait() # throws Queue.Empty if there are no lines to read 

所以,现在已经很晚了,但是我又遇到了同样的问题,现在有了一个更好的解决scheme。 只要使用pygtail :

Pygtail读取没有被读取的日志文件行。 它甚至会处理已经旋转的日志文件。 基于logcheck的logtail2( http://logcheck.org

理想情况下,我会有像tail.getNewData(),我可以每次需要更多的数据时调用

我们已经有一个和它非常好。 只要你想要更多的数据,就调用f.read() 。 它将开始读取前一次读取停止的位置,它将读取数据stream的末尾:

 f = open('somefile.log') p = 0 while True: f.seek(p) latest_data = f.read() p = f.tell() if latest_data: print latest_data print str(p).center(10).center(80, '=') 

对于逐行读取,使用f.readline() 。 有时,正在读取的文件将以部分读取行结束。 用f.tell()find当前文件的位置,使用f.seek()将文件指针移回到不完整行的开头。 看到这个ActiveState配方的工作代码。

你可以使用'tailer'库: https : //pypi.python.org/pypi/tailer/

它有一个选项来获得最后几行:

 # Get the last 3 lines of the file tailer.tail(open('test.txt'), 3) # ['Line 9', 'Line 10', 'Line 11'] 

它也可以遵循一个文件:

 # Follow the file as it grows for line in tailer.follow(open('test.txt')): print line 

如果有人想要像尾巴一样的行为,那么这似乎是一个不错的select。

另一个select是tailhead库,它提供了可以在你自己的模块中使用的tailhead工具的Python版本和API。

最初基于tailer模块,它的主要优点是能够按照path跟踪文件,即它可以处理文件重新创build时的情况。 此外,它还有一些针对各种边缘案例的错误修复。

您也可以使用'AWK'命令。
更多信息,请访问: http : //www.unix.com/shell-programming-scripting/41734-how-print-specific-lines-awk.html
awk可以用于尾部最后一行,最后几行或文件中的任何行。
这可以从Python中调用。

如果你在linux上,你可以用下面的方法在python中实现一个非阻塞的实现。

 import subprocess subprocess.call('xterm -title log -hold -e \"tail -f filename\"&', shell=True, executable='/bin/csh') print "Done" 

Python是“包含电池” – 它有一个很好的解决scheme: https : //pypi.python.org/pypi/pygtail

读取尚未读取的日志文件行。 记得上次完成的地方,并从那里继续。

 import sys from pygtail import Pygtail for line in Pygtail("some.log"): sys.stdout.write(line)