Как эффективно и в режиме реального времени выполнять отслеживание логов в торнадо-питоне - PullRequest
0 голосов
/ 05 мая 2019

У меня есть небольшое веб-приложение в проекте Python, основанном на торнадо, и мне нужно реализовать отслеживание журналов в реальном времени (одна из немногих вещей, в которых я застрял).Поведение должно быть похоже на Unix tail -f.Было бы хорошо, если бы это работало на всех платформах, но для начала достаточно просто UNIX.

Я искал много способов сделать это на stackoverflow и еще где, но не нашел то, что я ищу.Pythonic решения не годятся для отслеживания вращающихся журналов или файлов, которые иногда недоступны.

Поэтому я пошел по пути python subprocess.Однако я не мог использовать класс 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.поэтому я запутался в том, как это сделать.

Я бы хотел, чтобы журнал работал так же, как со стандартной командой linux tail -f.Он не должен блокировать мой цикл Tornado от других происходящих событий (таких как веб-запросы, обмен сообщениями через веб-сокет и т. Д.).Я должен быть в состоянии отправить line данные любому методу синхронизации или асинхронности в моей кодовой базе.

1 Ответ

3 голосов
/ 05 мая 2019

Используйте 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)
...