web-dev-qa-db-ja.com

Pythonロギング例外

現在、ラッパークラスを作成しています。例外を適切にログに記録できるようにしたいのですが、呼び出し元のメソッドが発生する例外を認識できるようにします。私のクラスは次のようになります。

import logging

log = logging.getLogger('module')

class MyAPIWrapper(library.APIClass):

    def __init__(self):
        self.log = logging.getLogger('module.myapiwrapper')


    def my_wrapper_method(self):
        try:
            response = self.call_api_method()
            return response.someData
        except APIException, e:
            self.log.exception('Oh noes!')
            raise e #Throw exception again so calling code knows it happened

ログに記録してから再度発生させて、呼び出し元のコードが何かを実行できるようにするためだけに、キャッチと例外について少し疑わしいです。ここでの適切なパターンは何ですか?

25
user130076

ログをキャッチすることに何の問題もありません。ただし、次のことをお勧めします。

    try:
        response = self.call_api_method()
    except APIException, e:  # or 'as e' depending on your Python version
        self.log.exception('Oh noes!')
        raise #Throw exception again so calling code knows it happened
    else:
        return response.someData

裸のraiseを実行するだけで、完全なトレースバック情報を保持できます。また、else句に例外がない場合にのみ発生するコードを配置する方が明確であり、例外をキャッチしている行が明確になります。

とにかくエラーを処理している場合は、呼び出し元のクラスがロギングを行うことも問題ありませんが、それはアプリにとって便利ではない可能性があります。

編集:try ... except ... else ... finallyのドキュメントは 複合ステートメント の下にあります。

29
agf

この方法は正しいですが、raise eの代わりにraiseを使用する必要があります。これにより、最後の例外が自動的に再発生します。これは、ブランケットexceptの使用が許容できると見なされるまれなケースの1つでもあります。

これは、Python docs on Handling Exceptions :から行っていることと非常によく似た例です。

最後のexcept句では、ワイルドカードとして機能するために、例外名を省略できます。この方法で実際のプログラミングエラーをマスクするのは簡単なので、これは細心の注意を払って使用してください。また、エラーメッセージを出力してから、例外を再発生させるためにも使用できます(呼び出し元が例外を処理できるようにします)。

import sys

try:
    f = open('myfile.txt')
    s = f.readline()
    i = int(s.strip())
except IOError as (errno, strerror):
    print "I/O error({0}): {1}".format(errno, strerror)
except ValueError:
    print "Could not convert data to an integer."
except:
    print "Unexpected error:", sys.exc_info()[0]
    raise
6
Andrew Clark