code

Python에서 로그 파일을 추적하려면 어떻게해야합니까?

codestyles 2020. 11. 23. 08:12
반응형

Python에서 로그 파일을 추적하려면 어떻게해야합니까?


차단 또는 잠금없이 Python에서 tail -F 또는 유사한 출력을 사용할 수 있도록하고 싶습니다. 여기 에서 그렇게하기위한 정말 오래된 코드를 찾았 지만 지금 쯤이면 더 나은 방법이나 라이브러리가 있어야한다고 생각합니다. 아는 사람 있나요?

이상적으로 tail.getNewData()는 더 많은 데이터를 원할 때마다 호출 할 수 있는 것과 같은 것이 있습니다.


비 차단

Linux를 사용하는 경우 (Windows는 파일에서 select 호출을 지원하지 않으므로) 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

이것은 또한 추가되는 새 줄을 인쇄하지만 tail 프로그램이 닫힐 때까지 차단됩니다 f.kill().


은 Using SH 모듈 (SH 설치 PIP) :

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

[최신 정보]

_iter= True가있는 sh.tail 은 생성기이므로 다음을 수행 할 수 있습니다.

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

그런 다음 다음을 사용하여 "getNewData"를 수행 할 수 있습니다.

new_data = tail.next()

테일 버퍼가 비어 있으면 더 많은 데이터가있을 때까지 차단됩니다 (질문에서이 경우 수행 할 작업이 명확하지 않음).

[최신 정보]

-f를 -F로 바꾸면 작동하지만 Python에서는 잠 깁니다. 가능하다면 새로운 데이터를 얻기 위해 호출 할 수있는 함수에 더 관심이 있습니다. – 일라이

컨테이너 생성기는 while True 루프 내부에 테일 호출을 배치하고 최종 I / O 예외를 포착하면 -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을 반환합니다. 그러나 파일에 액세스 할 수있는 경우 새 데이터가있을 때까지 여전히 차단됩니다. 이 경우에 무엇을하고 싶은지 불분명합니다.

Raymond Hettinger 접근 방식은 꽤 괜찮은 것 같습니다.

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 ''

이 생성기는 파일에 액세스 할 수 없거나 새 데이터가없는 경우 ''를 반환합니다.

[최신 정보]

마지막 두 번째 답변은 데이터가 부족할 때마다 파일 상단에 동그라미를칩니다. – 일라이

두 번째는 꼬리 프로세스가 끝날 때마다 마지막 10 줄을 출력 할 것이라고 생각합니다 -f. I / O 오류가있을 때마다 그렇습니다. tail --follow --retry동작은 멀지 않은이에서 나는에서 생각할 수있는 대부분의 경우 유닉스 같은 환경.

실제 목표가 무엇인지 설명하기 위해 질문을 업데이트하면 (꼬리를 모방하려는 이유-재시도) 더 나은 답을 얻을 수 있습니다.

마지막 대답은 실제로 꼬리를 따르지 않고 런타임에 사용 가능한 것을 읽습니다. – 일라이

물론 tail은 기본적으로 마지막 10 줄을 표시합니다. file.seek를 사용하여 파일 끝에 파일 포인터를 배치 할 수 있습니다. 적절한 구현은 독자에게 맡기겠습니다.

IMHO file.read () 접근 방식은 하위 프로세스 기반 솔루션보다 훨씬 우아합니다.


파일로 이동 하는 유일한 방법 tail -f은 실제로 파일을 읽고 가 0을 반환 하는 sleep경우 다시 시도하는 것 입니다. 다양한 플랫폼 readtail유틸리티는 플랫폼 별 트릭 (예 : kqueueBSD)을 사용하여 파일을 영원히 효율적으로 추적 필요없이 sleep.

따라서 tail -f순전히 Python 으로 좋은 것을 구현하는 것은 좋은 생각이 아닐 것입니다. 플랫폼 별 해킹에 의존하지 않고 최소 공분모 구현을 사용해야하기 때문입니다. 간단 subprocess하게 열고 tail -f별도의 스레드에서 줄을 반복하여 tailPython에서 비 차단 작업을 쉽게 구현할 수 있습니다 .

구현 예 :

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

So, this is coming quite late, but I ran into the same problem again, and there's a much better solution now. Just use pygtail:

Pygtail reads log file lines that have not been read. It will even handle log files that have been rotated. Based on logcheck's logtail2 (http://logcheck.org)


Ideally, I'd have something like tail.getNewData() that I could call every time I wanted more data

We've already got one and itsa very nice. Just call f.read() whenever you want more data. It will start reading where the previous read left off and it will read through the end of the data 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, '=')

For reading line-by-line, use f.readline(). Sometimes, the file being read will end with a partially read line. Handle that case with f.tell() finding the current file position and using f.seek() for moving the file pointer back to the beginning of the incomplete line. See this ActiveState recipe for working code.


You could use the 'tailer' library: https://pypi.python.org/pypi/tailer/

It has an option to get the last few lines:

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

And it can also follow a file:

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

If one wants tail-like behaviour, that one seems to be a good option.


All the answers that use tail -f are not pythonic.

Here is the pythonic way: ( using no external tool or library)

def follow(thefile):
     while True:
        line = thefile.readline()
        if not line or not line.endswith('\n'):
            time.sleep(0.1)
            continue
        yield line



if __name__ == '__main__':
    logfile = open("run/foo/access-log","r")
    loglines = follow(logfile)
    for line in loglines:
        print(line, end='')

Adapting Ijaz Ahmad Khan's answer to only yield lines when they are completely written (lines end with a newline char) gives a pythonic solution with no external dependencies:

def follow(file) -> Iterator[str]:
    """ Yield each line from a file as they are written. """
    line = ''
    while True:
        tmp = file.readline()
        if tmp is not None:
            line += tmp
            if line.endswith("\n"):
                yield line
                line = ''
        else:
            time.sleep(0.1)


if __name__ == '__main__':
    for line in follow(open("test.txt", 'r')):
        print(line, end='')

Another option is the tailhead library that provides both Python versions of of tail and head utilities and API that can be used in your own module.

Originally based on the tailer module, its main advantage is the ability to follow files by path i.e. it can handle situation when file is recreated. Besides, it has some bug fixes for various edge cases.


You can also use 'AWK' command.
See more at: http://www.unix.com/shell-programming-scripting/41734-how-print-specific-lines-awk.html
awk can be used to tail last line, last few lines or any line in a file.
This can be called from python.


If you are on linux you implement a non-blocking implementation in python in the following way.

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

Python is "batteries included" - it has a nice solution for it: https://pypi.python.org/pypi/pygtail

Reads log file lines that have not been read. Remembers where it finished last time, and continues from there.

import sys
from pygtail import Pygtail

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

참고URL : https://stackoverflow.com/questions/12523044/how-can-i-tail-a-log-file-in-python

반응형