首页 > 解决方案 > 如何在龙卷风python中以无阻塞的方式有效地实时进行日志拖尾

问题描述

我在基于龙卷风的 python 项目中有一个小 webapp,我需要实现实时日志拖尾(我坚持的少数事情之一)。行为应该类似于 unix 的tail -f. 如果它适用于所有平台,那就太好了,但对于初学者来说,unix 就足够了。

我在stackoverflow和其他地方搜索了很多方法,但没有找到我要找的东西。Pythonic 解决方案在跟踪轮换日志或文件有时无法访问方面并不好。

因此,我采用了 pythonsubprocess方式。Subprocess但是由于缺少示例,我无法使用龙卷风的课程。所以我尝试了正常的子流程run_in_executor。我不确定这是否是一个好方法,或者我是否会有未来的问题。


def tail(self, file):
        self.__process = subprocess.Popen(["tail", "-n", "1", "-f", file], stdout=subprocess.PIPE)

        while 1:
            line = self.__process.stdout.readline()
            print(line)
            # call a sync marked method and push line data
            asyncio.sleep(.0001)
            if not line:
                asyncio.sleep(.5)


    async def start_tail(self):
        # start here
        tornado.ioloop.IOLoop.current().run_in_executor(self.executor, self.tail, self.__log_path)
        pass

这里的问题是我需要推line到队列中。并且该队列位于标记的函数中async。要调用一个async方法,它说调用方法也应该是async. 在那种情况下,我最终会遇到错误:coroutines cannot be used with run_in_executor。所以我对如何完成这项工作感到困惑。

我希望日志拖尾能够像使用标准 linuxtail -f命令一样工作。它不应该阻止我的 Tornado 循环与其他正在发生的事情(例如 web 请求、websocket 消息传递等)。我应该能够将line数据发送到我的代码库中的任何同步或异步方法。

标签: pythonloggingasync-awaittornadotail

解决方案


使用tornado.process.Subprocess代替subprocess.Popen(及其STREAM选项代替PIPE)。这使您可以异步地从子进程中读取:

async def tail(self, file):
    self.__process = Subprocess(["tail", "-n", "1", "-f", file], stdout=Subprocess.STREAM)
    while True:
        line = await self.__process.stdout.read_until(b"\n")
        do_something(line)

def start_tail(self):
    IOLoop.current().spawn_callback(self.tail, self.__log_path)

推荐阅读