web-dev-qa-db-ja.com

Pythonでキャッチされていない例外を記録する

キャッチされない例外をloggingではなくstderrモジュールを介して出力するにはどうすればよいですか?

私はこれを行うための最良の方法が次のようになることを理解しています:

_try:
    raise Exception, 'Throwing a boring exception'
except Exception, e:
    logging.exception(e)
_

しかし、私の状況では、例外がキャッチされなかったときにlogging.exception(...)が自動的に呼び出された場合はreally Niceになります。

153
Jacob Marble

Nedが指摘したように、sys.excepthookは例外が発生してキャッチされないたびに呼び出されます。これの実際的な意味は、コードでsys.excepthookのデフォルトの動作をオーバーライドして、必要な処理を実行できることです(logging.exceptionの使用を含む)。

ストローマンの例として:

>>> import sys
>>> def foo(exctype, value, tb):
...     print 'My Error Information'
...     print 'Type:', exctype
...     print 'Value:', value
...     print 'Traceback:', tb
... 

sys.excepthookをオーバーライドします:

>>> sys.excepthook = foo

明らかな構文エラーをコミットし(コロンを省略)、カスタムエラー情報を取得します。

>>> def bar(a, b)
My Error Information
Type: <type 'exceptions.SyntaxError'>
Value: invalid syntax (<stdin>, line 1)
Traceback: None

sys.excepthookの詳細: http://docs.python.org/library/sys.html#sys.excepthook

126
Jacinda

以下に、他のいくつかのトリックを含む完全な小さな例を示します。

import sys
import logging
logger = logging.getLogger(__name__)
handler = logging.StreamHandler(stream=sys.stdout)
logger.addHandler(handler)

def handle_exception(exc_type, exc_value, exc_traceback):
    if issubclass(exc_type, KeyboardInterrupt):
        sys.__excepthook__(exc_type, exc_value, exc_traceback)
        return

    logger.error("Uncaught exception", exc_info=(exc_type, exc_value, exc_traceback))

sys.excepthook = handle_exception

if __== "__main__":
    raise RuntimeError("Test unhandled")
  • コンソールpythonプログラムがCtrl + Cで終了できるように、KeyboardInterruptを無視します。

  • 例外の書式設定は、Pythonのログモジュールに完全に依存しています。

  • サンプルハンドラーでカスタムロガーを使用します。これにより、未処理の例外がstderrではなくstdoutに変更されますが、この同じスタイルのあらゆる種類のハンドラーをロガーオブジェクトに追加できます。

144
gnu_lorien

メソッドsys.excepthookは、例外がキャッチされなかった場合に呼び出されます: http://docs.python.org/library/sys.html#sys.excepthook

例外が発生してキャッチされなかった場合、インタープリターは3つの引数、例外クラス、例外インスタンス、およびトレースバックオブジェクトを指定してsys.excepthookを呼び出します。対話型セッションでは、これは制御がプロンプトに戻る直前に発生します。 Pythonプログラムでは、これはプログラムが終了する直前に発生します。このようなトップレベルの例外の処理は、sys.excepthookに別の3つの引数関数を割り当てることでカスタマイズできます。

26
Ned Batchelder

何故なの:

import sys
import logging
import traceback

def log_except_hook(*exc_info):
    text = "".join(traceback.format_exception(*exc_info))
    logging.error("Unhandled exception: %s", text)

sys.excepthook = log_except_hook

None()

上記はsys.excepthookの出力です。

$ python tb.py
ERROR:root:Unhandled exception: Traceback (most recent call last):
  File "tb.py", line 11, in <module>
    None()
TypeError: 'NoneType' object is not callable

以下は、sys.excepthookがコメント化された出力です。

$ python tb.py
Traceback (most recent call last):
  File "tb.py", line 11, in <module>
    None()
TypeError: 'NoneType' object is not callable

唯一の違いは、前者の最初の行の先頭にERROR:root:Unhandled exception:があることです。

18
Tiago Coutinho

Jacindaの答えを基にして、ロガーオブジェクトを使用するには:

def catchException(logger, typ, value, traceback):
    logger.critical("My Error Information")
    logger.critical("Type: %s" % typ)
    logger.critical("Value: %s" % value)
    logger.critical("Traceback: %s" % traceback)

# Use a partially applied function
func = lambda typ, value, traceback: catchException(logger, typ, value, traceback)
sys.excepthook = func
6
Mike

アプリエントリの呼び出しをtry...exceptブロックでラップして、キャッチされていないすべての例外をキャッチしてログに記録(および場合によっては再発生)できるようにします。例えば。の代わりに:

if __== '__main__':
    main()

これを行う:

if __== '__main__':
    try:
        main()
    except Exception as e:
        logger.exception(e)
        raise
5
flaviovs

モジュールの最上部でstderrをファイルにリダイレクトし、そのファイルを最下部に記録することができます

sock = open('error.log', 'w')               
sys.stderr = sock

doSomething() #makes errors and they will log to error.log

logging.exception(open('error.log', 'r').read() )
3
JiminyCricket

@gnu_lorienの答えは良い出発点を与えてくれましたが、私のプログラムは最初の例外でクラッシュします。

カスタマイズされた(および/または)改善されたソリューションが付属していました。これは、@handle_error

import logging

__author__ = 'ahmed'
logging.basicConfig(filename='error.log', level=logging.DEBUG)


def handle_exception(exc_type, exc_value, exc_traceback):
    import sys
    if issubclass(exc_type, KeyboardInterrupt):
        sys.__excepthook__(exc_type, exc_value, exc_traceback)
        return
    logging.critical(exc_value.message, exc_info=(exc_type, exc_value, exc_traceback))


def handle_error(func):
    import sys

    def __inner(*args, **kwargs):
        try:
            return func(*args, **kwargs)
        except Exception, e:
            exc_type, exc_value, exc_tb = sys.exc_info()
            handle_exception(exc_type, exc_value, exc_tb)
        finally:
            print(e.message)
    return __inner


@handle_error
def main():
    raise RuntimeError("RuntimeError")


if __== "__main__":
    for _ in xrange(1, 20):
        main()
2
guneysus