web-dev-qa-db-ja.com

Pythonでstderrをリダイレクトする方法は?

Pythonスクリプトのすべての出力をログに記録したいと思います。

import sys

log = []

class writer(object):
    def write(self, data):
        log.append(data)

sys.stdout = writer()
sys.stderr = writer()

ここで、「何かを印刷」すると、ログに記録されます。しかし、たとえば「print 'something#」と言って構文エラーを発生させても、ログに記録されず、代わりにコンソールに表示されます。

Pythonインタプリタからのエラーもキャプチャするにはどうすればよいですか?

私はここで可能な解決策を見ました:

http://www.velocityreviews.com/forums/showpost.php?p=1868822&postcount=

しかし、2番目の例は/ dev/nullにログインします-これは私が望むものではありません。上記の例やStringIOなどのリストにログインしたいのですが...

また、できれば、サブプロセスを作成したくない(そして、そのstdoutとstderrを別のスレッドで読み取らない)ことが望ましい。

21
EcirH

同じコードのコンパイル中にエラーをキャプチャできるPythonコードでは何もできません。どうすればできますか?コンパイラがコードのコンパイルを完了できない場合、実行されません。コードなので、リダイレクトはまだ有効になっていません。

これが(不要な)サブプロセスの出番です。標準出力をリダイレクトするPythonコードを記述してから、Pythonインタープリタを呼び出して、他のコードをコンパイルします。 。

7
Ned Batchelder

Stderrを次のようにファイルにキャプチャする作業用に作成したソフトウェアがあります。

import sys
sys.stderr = open('C:\\err.txt', 'w')

確かにそれは可能です。

あなたの問題は、あなたが作家の2つのインスタンスを作成していることだと思います。

多分もっともっと何か:

import sys

class writer(object):
    log = []

    def write(self, data):
        self.log.append(data)

logger = writer()
sys.stdout = logger
sys.stderr = logger
21
KingRadical

簡単な方法は考えられません。 pythonプロセスの標準エラーは、pythonファイルオブジェクト(C対python))よりも低いレベルにあります。

pythonスクリプトを2番目にラップするpythonスクリプトを使用し、subprocess.Popenを使用することができます。また、次のような魔法を1つのスクリプトで実行することもできます。

import os
import subprocess
import sys

cat = subprocess.Popen("/bin/cat", stdin=subprocess.PIPE, stdout=subprocess.PIPE)
os.close(sys.stderr.fileno())
os.dup2(cat.stdin.fileno(), sys.stderr.fileno())

次に、select.poll()を使用してcat.stdoutを定期的にチェックし、出力を見つけます。

はい、それはうまくいくようです。

私が予測する問題は、ほとんどの場合、pythonによってstderrに出力されるものは、それが終了しようとしていることを示します。これを処理するより一般的な方法は、例外によるものです。

---------編集

どういうわけか私はos.pipe()関数を逃しました。

import os, sys
r, w = os.pipe()
os.close(sys.stderr.fileno())
os.dup2(w, sys.stderr.fileno())

次に、rから読み取ります

6
user227667

実際、linux/mac osを使用している場合は、ファイルリダイレクトを使用してそれを実行できます。たとえば、「a.py」を実行して、生成するすべてのメッセージをファイル「a.out」に記録する場合は、次のようになります。

python a.py 2>&1 > a.out

最初の部分はstderrをstdoutにリダイレクトし、2番目の部分はa.outと呼ばれるファイルにリダイレクトします。

Linux/Unixのリダイレクト演算子の詳細なリストについては、 https://askubuntu.com/questions/420981/how-do-i-save-terminal-output-to-a-file を参照してください。

5
VitleysingurQ

python 3.5なので、 contextlib.redirect_stderr

with open('help.txt', 'w') as f:
    with redirect_stdout(f):
        help(pow)
2
max

エラーがある場合、Pythonはコードを実行しません。ただし、catch例外を使用して、スクリプトを別のスクリプトにインポートできます。例:

Script.py

print 'something#

FinalScript.py

from importlib.machinery import SourceFileLoader

try:
    SourceFileLoader("main", "<SCRIPT PATH>").load_module()
except Exception as e:
    # Handle the exception here
0
ColdGrub1384
import sys
import tkinter

# ********************************************

def mklistenconsswitch(*printf: callable) -> callable:
    def wrapper(*fcs: callable) -> callable:
        def newf(data):
            [prf(data) for prf in fcs]
        return newf
    stdoutw, stderrw = sys.stdout.write, sys.stderr.write
    funcs = [(wrapper(sys.stdout.write, *printf), wrapper(sys.stderr.write, *printf)), (stdoutw, stderrw)]
    def switch():
        sys.stdout.write, sys.stderr.write = dummy = funcs[0]
        funcs[0] = funcs[1]
        funcs[1] = dummy
    return switch

# ********************************************

def datasupplier():
    i = 5.5
    while i > 0:
        yield i
        i -= .5

def testloop():
    print(supplier.__next__())
    svvitch()
    root.after(500, testloop)

root = tkinter.Tk()
cons = tkinter.Text(root)
cons.pack(fill='both', expand=True)
supplier = datasupplier()
svvitch = mklistenconsswitch(lambda text: cons.insert('end', text))
testloop()
root.mainloop()
0
yagami raito

Windowsからの出力とエラーをルーティングするには、Pythonファイルの外で次のコードを使用できます。

python a.py 1> a.out 2>&1

ソース: https://support.Microsoft.com/en-us/help/110930/redirecting-error-messages-from-command-Prompt-stderr-stdout

0
Miguel Garces

ネッドの答えに追加すると、コンパイル中にその場でエラーをキャプチャすることは困難です。

スクリプトに複数の印刷ステートメントを記述し、ファイルにstdoutを実行できます。エラーが発生すると、ファイルへの書き込みが停止します。コードをデバッグするには、最後にログに記録された出力を確認し、それ以降にスクリプトを確認します。


次のようなもの:

# Add to the beginning of the script execution(eg: if __name__ == "__main__":).
from datetime import datetime
dt = datetime.now()
script_dir = os.path.dirname(os.path.abspath(__file__))      # gets the path of the script
stdout_file = script_dir+r'\logs\log'+('').join(str(dt.date()).split("-"))+r'.log'
sys.stdout = open(stdout_file, 'w')

これにより、ログファイルが作成され、印刷ステートメントがファイルにストリーミングされます。


注:コードの最後から2行目のscript_dirと連結している間、ファイルパスのエスケープ文字に注意してください。生の文字列に似たものが必要になる場合があります。 this thread で確認できます。

0
rzskhr