LINUX.ORG.RU

tail -f на питоне перестает следить за файлом/перестаёт писать в конечный файл

 


0

3

Всем привет. Проблема заключается в том, что через какое то время программа ниже перестаёт либо писать в файл, либо отслеживать нужное в исходном - этого я пока понять не могу. Сама программа продолжает висеть в процессах, отсюда я смею предположить, что она какбэ продолжает работать. А вот что нарушает её нормальное функционирование понять не могу

import subprocess
import os
import sys


def tail_forever(file, pat):
        os.chdir(sys.path[0])
        with open("log", "a+") as log:
            try:
                with open(file, "r") as f:
                    try:
                        p = subprocess.Popen(["tail", "-f", file], stdout=subprocess.PIPE)
                        while 1:
                            line = p.stdout.readline().decode()
                            if pat in line:
                                 log.write(line)
                                log.flush()
                            elif not line:
                                break
                    except KeyboardInterrupt:
                        print("KB INT")
                        log.write("INTERRUPTED FROM KB: ")
                        print("AFTER KB")
                        log.flush()
                    except Exception:
                        log.write("UNEXPECTED ERROR: ", sys.exc_info()[0])
                        log.flush()
                    finally:
                        log.close()
                        sys.exit("EXIT")
            finally:
                f.close()


if __name__ == "__main__":
    tail_forever(sys.argv[1], sys.argv[2])

Есть у кого какие идеи? Всем заранее спасибо. Версия питона 2.6.6, если что

★★

Последнее исправление: SpaceRanger (всего исправлений: 4)

Есть у кого какие идеи

Версия питона 2.6.6

Идея первая - ты некрофил.

Идея вторая - logrotate нету? Файл тот же пишется все время? Если он заменяется по logrotate то такие спецэффекты вполне бывают

upcFrost ★★★★★
()
Последнее исправление: upcFrost (всего исправлений: 1)
Ответ на: комментарий от usi_svobodi

найди батарейки

Такой себе совет. Недавно изучал «батарейки» нашего проекта на предмет «кто сожрал память». Нашёл прям тонны интересных технических решений вроде втыкания numpy где можно и нельзя или хранения гигансткого одноразового бинаря в константах. Не в плане что я против либ, но нужно отдавать себе отчёт что и как там происходит прежде чем искать «халяву на pypi».

upcFrost ★★★★★
()
Ответ на: комментарий от upcFrost

Идея первая - ты некрофил.

Щито поделать, вот такое стоит и обновиться нет никакой возможности.

Идея вторая - logrotate нету? Файл тот же пишется все время? Если он заменяется по logrotate то такие спецэффекты вполне бывают

logrotate нет, инфа сотка.

SpaceRanger ★★
() автор топика
import subprocess
import os
import sys



def tail_forever(file, pat):
    os.chdir(sys.path[0])
    with open("log", "a+") as log:
        try:
            p = subprocess.Popen(["tail", "-F", file], stdout=subprocess.PIPE)
            while 1:
                line = p.stdout.readline().decode()
                if pat in line:
                    log.write(line)
                    log.flush()
                elif not line:
                    break
        except KeyboardInterrupt:
            print("KB INT")
            log.write("INTERRUPTED FROM KB: ")
            print("AFTER KB")
            log.flush()
        except Exception:
            log.write("UNEXPECTED ERROR: ", sys.exc_info()[0])
            log.flush()
        finally:
            log.close()
            sys.exit("EXIT")


if __name__ == "__main__":
    tail_forever(sys.argv[1], sys.argv[2])

Подумал, что наверное не стоит открывать файл, за которым идёт наблюдение, ибо tail и так его открывает. ПОнаблюдаю. МОжет быть в этом проблема

SpaceRanger ★★
() автор топика
Последнее исправление: SpaceRanger (всего исправлений: 2)
Ответ на: комментарий от upcFrost

в интернетах пишут, что полагаться на готовенькие библиотеки из pypi это примерно то же самое, что ставить что-то из AUR - может норм работать, а может и отвалиться в самый ответственный момент.

SpaceRanger ★★
() автор топика
Ответ на: комментарий от SpaceRanger

Прижми IO диска :) скорее всего увидишь отвал хвоста

Стремное занятие писать на разделяемый ресурс без буфера, насколько помню file.write в питоне не гарантирует асинхронность и консистентность

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

Morin ★★★★
()
Последнее исправление: Morin (всего исправлений: 1)
Ответ на: комментарий от SpaceRanger

tail пишет быстрее, чем твоя программа читает.

Почему бы вместо подпроцесса, не реализовать tail на самом python, это делается элементарно? Всё будет гораздо проще и надежнее.

emorozov
()
Ответ на: комментарий от emorozov

Нет. Скорость записи тут не причем. Broken pipe это когда её закрыли с другой стороны.

А закрывает он её когда выполняется

                elif not line:
                    break
Я без понятия что это :)

Про свою реализацию: надёжней - может быть, но не проще.

Пересоздание читаемого файла нужно отслеживать.

vel ★★★★★
()
Ответ на: комментарий от SpaceRanger

А по-моему нормальная строчка, так как line не может быть пустой ввиду того, что блокирующий readline() всегда возвращает строку вместе с символом переноса \n. Мне кажется, что условие not line вообще никогда не может выполнится. Нет?

ASavonte
()
Ответ на: комментарий от ASavonte

нет. Прога просто вываливается с

tail: write error: Broken pipe
tail: write error

а в файле для записи ничего нет, хотя я пытаюсь с помощью except хоть какую то инфу об ошибке туда записать

SpaceRanger ★★
() автор топика
Ответ на: комментарий от vel

Удаление

elif not line:
   break

не помогло. Да и , разобравшись, я подумал, что это не особо то и влияло на ход выполнения

Кстати, а как отследить пересоздание остлеживаемого файла? гугол говорит про библиотеку watchdog, оно?

SpaceRanger ★★
() автор топика
Последнее исправление: SpaceRanger (всего исправлений: 1)

Господа! Кажется, проблема действительно в том, что отслеживаемый файл имеет свойство пересоздаваться (видимо, по причине переполнения или может по таймеру какому. Сие мне неведомо). Буду гуглить, как отследивать пересоздание

SpaceRanger ★★
() автор топика
Ответ на: комментарий от SpaceRanger

tail -F как раз и должен был избавить от этой проблемы. Его можно запускать вообще без существующего в данный момент файла. Если же файл обрезается (truncate), то он тоже это должен нормально обрабатывать.

ASavonte
()
Ответ на: комментарий от ASavonte

хммм…да, опытным путём выяснил, что это не пересоздание файла виновно… если перенаправить

p = subprocess.Popen(["tail", "-F", file], stdout=subprocess.PIPE, stderr=log)

то в log вижу

tail: write error: Broken pipe
tail: write error

то есть инфы столько же, сколько и было то есть маловато

SpaceRanger ★★
() автор топика
Ответ на: комментарий от SpaceRanger

log.write("UNEXPECTED ERROR: ", sys.exc_info()[0])

write() же не print(), у него только один параметр. Вот и получается, что decode() бросает исключение и во время его обработки возникает новое, программа на питоне завершается, а tail так и остаётся висеть в процессах. Наверное)

ASavonte
()
Ответ на: комментарий от ASavonte

ну просто я встречал в инторнете подобный фокус, да и иде не ругается. Но на всякий случай поправил

import subprocess
import os
import sys



def tail_forever(file, pat):
    os.chdir(sys.path[0])
    with open("log", "a+") as log:
        try:
            p = subprocess.Popen(["tail", "-F", file], stdout=subprocess.PIPE, stderr=log)
            while 1:
               # line = p.stdout.readline().decode()
                line = p.stdout.readline()
                if pat in line:
                    # print(line.strip())
                    log.write(line)
                    log.flush()
                    # print(f"[{datetime.datetime.now()}]  {line.decode().strip()}")
                else:
                    pass
        except KeyboardInterrupt:
            print("KB INT")
            log.write("INTERRUPTED FROM KB: ")
            print("AFTER KB")
            log.flush()
        except Exception:
            log.write("UNEXPECTED ERROR: ")
            log.write(sys.exc_info()[0])
            log.flush()
        finally:
            log.close()
            sys.exit("EXIT")


if __name__ == "__main__":
    tail_forever(sys.argv[1], sys.argv[2])
SpaceRanger ★★
() автор топика
Ответ на: комментарий от ASavonte

У него python 2.6. Надо from __future__ import print_function или что-то в этом роде. Не помню уже было ли это в 2.6 и вспоминать не хочу.

IMHO, правильный подход: если не обновиться, то хотя бы скомпилять py3 вручную (или через pyenv).

emorozov
()
import subprocess
import os
import sys



def tail_forever(file, pat):
    os.chdir(sys.path[0])
    with open("log", "a+") as log:
        try:
            p = subprocess.Popen(["tail", "-F", file], stdout=subprocess.PIPE, stderr=log)
            while 1:
                line = p.stdout.readline()
                if pat in line:
                    log.write(line)
                    log.flush()
                else:
                    pass
        except KeyboardInterrupt:
            log.write("INTERRUPTED FROM KB: ")
            log.flush()
        except Exception:
            log.write("UNEXPECTED ERROR: ")
            log.write(sys.exc_info()[0])
            log.flush()
        finally:
            log.close()
            sys.exit("EXIT")


if __name__ == "__main__":
    tail_forever(sys.argv[1], sys.argv[2])

Вобщем, вот такой вариант вполне себе работает

SpaceRanger ★★
() автор топика
Ответ на: комментарий от SpaceRanger
def tail_forever(file, pat):
    os.chdir(sys.path[0])
    with open("log", "a+") as log:
        def out(l):
            for s in l:
                log.write(s)
            log.flush()

        try:
            p = subprocess.Popen(["tail", "-F", file], stdout=subprocess.PIPE, stderr=log)
            while 1:
                line = p.stdout.readline()
                if pat in line:
                    out([line])
        except KeyboardInterrupt:
            out(["INTERRUPTED FROM KB: "])
        except Exception:
            out(["UNEXPECTED ERROR: ",sys.exc_info()[0]])
        finally:
            log.close()
            sys.exit("EXIT")


if __name__ == "__main__":
    tail_forever(sys.argv[1], sys.argv[2])
qulinxao3
()