web-dev-qa-db-ja.com

Pythonでログファイルを作成するにはどうすればよいですか?

Tail -Fの出力を、ブロックやロックなしでPythonで利用できるようにしたいと思います。それを行うための本当に古いコードを見つけました here 、しかし、今までと同じことをするためのより良い方法またはライブラリがあるはずだと思います。誰もが知っていますか?

理想的には、tail.getNewData()のようなものを用意して、より多くのデータが必要になるたびに呼び出すことができます。

63
Eli

そのため、これはかなり遅れていますが、私は同じ問題に再び遭遇しました。 pygtail を使用するだけです:

Pygtailは、読み取られていないログファイルの行を読み取ります。ローテーションされたログファイルも処理します。 logcheckのlogtail2に基づく( http://logcheck.org

12
Eli

ノンブロッキング

Linuxを使用している場合(Windowsはファイルの選択呼び出しをサポートしていないため)、サブモジュールを選択モジュールとともに使用できます。

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()でテールプログラムが閉じられるまでブロックされます。

60
Matt

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)

[更新]

_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を返します。ただし、ファイルにアクセスできる場合、新しいデータが見つかるまでブロックされます。この場合にあなたが何をしたいのかは私には不明のままです。

レイモンド・ヘッティンガーのアプローチはかなり良いようです:

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

このジェネレータは、ファイルにアクセスできなくなった場合、または新しいデータがない場合に ''を返します。

[更新]

最後から2番目の回答は、データがなくなるたびにファイルの先頭に移動します。 –エリ

2番目は、末尾プロセスが終了するたびに最後の10行を出力すると思います。-fでは、I/Oエラーが発生するたびになります。 tail --follow --retryの動作は、Unixのような環境で考えることができるほとんどの場合、これからそれほど遠くありません。

おそらく、あなたの本当の目標(テールを模倣したい理由-再試行)を説明するために質問を更新すると、より良い答えが得られます。

最後の答えは、実際には尾をたどらず、単に実行時に利用可能なものを読み取ります。 –エリ

もちろん、tailはデフォルトで最後の10行を表示します... file.seekを使用して、ファイルポインターをファイルの末尾に配置できます。読者に演習として適切な実装を任せます。

私見file.read()アプローチは、サブプロセスベースのソリューションよりもはるかにエレガントです。

33
Paulo Scardine

唯一のportabletail -fへの方法は、実際には、sleepが0を返す場合、ファイルから読み取り、(readの後)再試行するように見える。さまざまなプラットフォームのtailユーティリティは、プラットフォーム固有のトリック(たとえば、BSDのkqueue)を使用して、sleepを必要とせずにファイルを効率的に永遠にテールします。

したがって、Pythonに純粋なtail -fを実装することは、プラットフォーム固有のハッキングに頼らずに最小公分母の実装を使用する必要があるため、おそらく良いアイデアではありません。単純なsubprocessを使用してtail -fを開き、別のスレッドで行を反復処理することにより、Pythonで非ブロッキングtail操作を簡単に実装できます。

実装例:

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
22
nneonneo

理想的には、より多くのデータが必要になるたびに呼び出すことができるtail.getNewData()のようなものがあります

私たちはすでに1つと非常に素晴らしいものを持っています。 もっとデータが必要なときはいつでも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レシピ をご覧ください。

8

Tail -fを使用するすべての答えはPythonicではありません。

Pythonの方法は次のとおりです:(外部のツールやライブラリを使用しない)

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



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

「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

尾のような振る舞いを望むなら、それは良い選択肢のようです。

5
Haroldo_OK

Ijaz Ahmad Khanの answer を完全に記述された行(改行文字で終わる行)のみを生成するように適合させると、外部依存関係のないPythonのソリューションが得られます。

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 __== '__main__':
    for line in follow(open("test.txt", 'r')):
        print(line, end='')
3
Isaac Turner

別のオプションは、 tailhead ライブラリです。このライブラリは、独自のモジュールで使用できるtailおよびheadユーティリティとAPIのPythonバージョンの両方を提供します。

もともとtailerモジュールに基づいていましたが、その主な利点は、ファイルをパスで追跡できることです。つまり、ファイルが再作成されたときの状況を処理できます。さらに、さまざまなEdgeケースのバグ修正がいくつかあります。

2
Kentzo

「AWK」コマンドを使用することもできます。
詳細: http://www.unix.com/Shell-programming-scripting/41734-how-print-specific-lines-awk.html
awkを使用して、最後の行、最後の数行、またはファイル内の任意の行を末尾に付けることができます。
これは、pythonから呼び出すことができます。

0
Madhusoodan

Linuxを使用している場合は、次の方法でpythonにノンブロッキング実装を実装します。

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