Как я могу закрепить файл журнала в Python?

Я хотел бы сделать вывод tail -F или что-то подобное доступным мне в Python без блокировки или блокировки. Я нашел какой-то действительно старый код, чтобы сделать это здесь , но я думаю, что на данный момент должен быть лучший способ или библиотека, чтобы сделать то же самое. Кто-нибудь знает об одном?

В идеале у меня было бы что-то вроде tail.getNewData() которое я мог бы вызвать каждый раз, когда мне нужно больше данных.

  • Как реализовать питонический эквивалент хвоста -F?
  • 10 Solutions collect form web for “Как я могу закрепить файл журнала в Python?”

    Без блокировки

    Если вы используете Linux (так как окна не поддерживают выбор вызова в файлах), вы можете использовать модуль подпроцесса вместе с модулем 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) 

    Это проверяет выходной канал для новых данных и печатает его, когда он доступен. Обычно time.sleep(1) и print f.stdout.readline() заменяются полезным кодом.

    блокировка

    Вы можете использовать модуль подпроцесса без дополнительных вызовов модуля.

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

    Это также будет печатать новые строки по мере их добавления, но он будет блокироваться до закрытия хвостовой программы, возможно, с помощью 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) 

    [Обновить]

    Поскольку sh.tail с _iter = True является генератором, вы можете:

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

    Затем вы можете «getNewData» с:

     new_data = tail.next() 

    Обратите внимание: если буфер хвоста пуст, он будет блокироваться, пока не появится больше данных (из вашего вопроса не ясно, что вы хотите сделать в этом случае).

    [Обновить]

    Это работает, если вы замените -f на -F, но в Python он будет заблокирован. Меня больше интересовала бы функция, которую я мог бы вызвать, чтобы получить новые данные, когда захочу, если это возможно. – Эли

    Генератор контейнера, помещающий хвостовой вызов в течение некоторого времени. Истинный цикл и перехватывание возможных исключений ввода-вывода будет иметь почти такой же эффект -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 '' 

    Этот генератор вернет '', если файл становится недоступным или нет новых данных.

    [Обновить]

    От второго до последнего ответа круги вокруг верхней части файла кажутся всякий раз, когда у него заканчиваются данные. – Эли

    Я думаю, что второй будет выводить последние десять строк всякий раз, когда заканчивается хвостовой процесс, который с -f возникает всякий раз, когда возникает ошибка ввода-вывода. tail --follow --retry поведение находится недалеко от этого, для большинства случаев, о которых я могу думать в unix-подобных средах.

    Возможно, если вы обновите свой вопрос, чтобы объяснить, какова ваша реальная цель (причина, по которой вы хотите подражать хвосту), вы получите лучший ответ.

    Последний ответ фактически не следует за хвостом и просто читает, что доступно во время выполнения. – Эли

    Конечно, хвост покажет последние 10 строк по умолчанию … Вы можете поместить указатель файла в конец файла с помощью file.seek, я оставил правильную реализацию в качестве упражнения для читателя.

    ИМХО метод file.read () намного шире, чем решение на основе подпроцесса.

    Единственный переносимый путь к tail -f – файл, по-видимому, является, по сути, чтением и повторением (после sleep ), если read возвращает 0. Утилиты tail на разных платформах используют трюки для конкретной платформы (например, kqueue на BSD ), чтобы эффективно закрепить файл навсегда, не требуя sleep .

    Таким образом, реализация хорошего tail -f исключительно в Python, вероятно, не очень хорошая идея, так как вам придется использовать реализацию с наименьшим общим знаменателем (не прибегая к хакам платформы). Используя простой subprocess для открытия tail -f и итерации по линиям в отдельном потоке, вы можете легко реализовать неблокирующую операцию tail в Python.

    Пример реализации:

     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 

    Итак, это происходит довольно поздно, но я снова столкнулся с той же проблемой, и сейчас есть гораздо лучшее решение. Просто используйте pygtail :

    Pygtail читает строки журнала, которые не были прочитаны. Он даже обрабатывает файлы журналов, которые были повернуты. На основе logtail2 журнала ( http://logcheck.org )

    В идеале у меня было бы что-то вроде tail.getNewData (), которое я мог бы вызывать каждый раз, когда мне нужно больше данных

    У нас уже есть один и его очень хороший. Просто позвоните f.read (), когда вам нужно больше данных. Он начнет чтение, когда предыдущее чтение будет остановлено, и оно прочитает конец потока данных:

     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 () находит текущую позицию файла и использует 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 

    Если кто-то хочет походить на хвост, это кажется хорошим вариантом.

    Другим вариантом является библиотека tailhead которая предоставляет как версии Python tail и head утилит, так и API, которые могут использоваться в вашем собственном модуле.

    Первоначально на tailer модуля tailer , его основным преимуществом является возможность отслеживания файлов по пути, то есть он может обрабатывать ситуацию, когда файл воссоздается. Кроме того, у него есть некоторые исправления ошибок для разных случаев.

    Вы также можете использовать команду «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 – это «батареи в комплекте» – у него есть хорошее решение для него: https://pypi.python.org/pypi/pygtail

    Читает строки журнала, которые не были прочитаны. Помнит, где он закончил последний раз, и продолжается оттуда.

     import sys from pygtail import Pygtail for line in Pygtail("some.log"): sys.stdout.write(line) 
    Python - лучший язык программирования в мире.