5

私は調査ツールを作成していますが、最近、「print」ステートメントの使用から、Python に組み込まれているロガー機能の使用に切り替えました。これにより、出力を画面にダンプするだけでなく、ファイルにダンプするオプションをユーザーに提供できるようになると私は考えました。

ここまでは順調ですね。私のコードの Python の部分では、「logger.info」と「logger.error」を使用して、画面とファイルの両方にダンプします。「logger」はモジュール全体のロガーです。この部分は魅力のように機能します。

ただし、いくつかの時点で、「subprocess.call」を使用して、シェルを介して実行可能ファイルを実行します。したがって、コード全体に次のような行があります

proc = subprocess.call(command)

このコマンドからの出力は、いつものように画面に出力されますが、ユーザーが指定したファイルにはダンプされません。

考えられるオプションの 1 つは、ファイルへのパイプを開くことです。

proc = subprocess.call(command, stdout=f, stderr=subprocess.OUTPUT)

しかし、それはファイルにのみダンプし、画面にはダンプしません。

基本的に、私の質問はこれに要約されます: subprocess.call 専用のファイル用に別のハンドラーを作成することなく、既存のロガーを活用できる方法はありますか? (おそらく、出力をロガーにリダイレクトすることによってですか?)または、現在のセットアップを考えると、これは不可能ですか?後者の場合、どうすればセットアップを改善できますか?

(ああ、また、ログが「リアルタイム」であると、実行可能ファイルからのメッセージが受信されたときにログに記録されるようになります。)

助けてくれてありがとう!:)

4

2 に答える 2

3

stdoutファイルにパイプする代わりに、それを にパイプしてPIPE、そのパイプから読み取り、ロガーに書き込むことができます。このようなもの:

proc = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.OUTPUT)
for line in proc.stdout:
    logging.info(line)

ただし、さらに簡単な答えがあります。ファイル ハンドルを持つファイルのようなオブジェクトを使用する必要がありますが、各行を に渡すパイプの上にオブジェクトを作成できますlogging。このオブジェクトを自分で作成することもできますが、@unutbu が言うように、誰かがこの質問で既にそれを行っています。そう:

with StreamLogger(logging.INFO) as out:
    proc = subprocess.call(command, stdout=out, stderr=subprocess.OUTPUT)

もちろん、一時的にラップstdoutしてロガーに書き込み、出力を単に渡すこともできます。たとえば、この紛らわしい同じ名前のクラスを使用します。

with StreamLogger('stdout'):
    proc = subprocess.call(command, stderr=subprocess.OUTPUT)
于 2012-12-17T23:50:07.877 に答える
3

unutbuのコメントは良いです。Lennart's answerをご覧ください。

必要なのは の機能のようなものですteeが、subprocessモジュールは OS ハンドルのレベルで動作します。つまり、サブプロセスによって書き込まれたデータは Python コードでは見ることができません。それに書かれているものは何でも印刷します。

レナートの答えを使用するだけでなく、次のようなサードパーティのライブラリを使用して、この種のことを行うことができますsarge(開示:私はそのメンテナーです)。ロギング以外にも機能します。次のような出力を生成するプログラムがあるとします。

# echotest.py
import time
for i in range(10):
    print('Message %d' % (i + 1))

スクリプトでそれをキャプチャし、ログに記録して画面に出力します。

#subptest.py
from sarge import capture_stdout
import logging
import sys

logging.basicConfig(filename='subptest.log', filemode='w',
                    level=logging.INFO)

p = capture_stdout('python echotest.py', async=True)
while True:
    line = p.stdout.readline()
    line = line.strip()
    # depending on how the child process generates output,
    # sometimes you won't see anything for a bit. Hence only print and log
    # if you get something
    if line:
        print(line)
        logging.info(line)

    # Check to see when we can stop - after the child is done.
    # The return code will be set to the value of the child's exit code,
    # so it won't be None any more.

    rc = p.commands[0].process.poll()
    # if no more output and subprocess is done, break
    if not line and rc is not None:
        break

上記のスクリプトを実行すると、コンソールに出力されます。

$ python subptest.py 
Message 1
Message 2
Message 3
Message 4
Message 5
Message 6
Message 7
Message 8
Message 9
Message 10

ログ ファイルを確認すると、次のように表示されます。

$ cat subptest.log 
INFO:root:Message 1
INFO:root:Message 2
INFO:root:Message 3
INFO:root:Message 4
INFO:root:Message 5
INFO:root:Message 6
INFO:root:Message 7
INFO:root:Message 8
INFO:root:Message 9
INFO:root:Message 10
于 2012-12-17T23:55:08.107 に答える