Pythonを使っているときに、ログを取るのを怠ってエラーが見つからずに苦労したので、ちゃんとログを取りましょう、という話です。(Pythonに慣れている方には、おそらく常識レベルの話だと思います)
普通に処理をしている場合は、予期しない例外が発生すると標準エラー出力に例外のスタックトレースが出力されます。しかし、標準エラー出力を潰した後はスタックトレースが出力されません。
以下のような場合に問題になります。
- daemon化する場合
- スレッドを実行する場合
順に説明します。
daemon化する場合
double forkによるdaemon化については、Pythonでは以下のページの例のように行います。
Double forkによるプロセスのデーモン化と、ファイル変更時の自動サーバーリロードの実装 (Python)
この場合、標準エラー出力が潰されているので、 daemon化した後に例外が発生しても、 例外のスタックトレースはどこにも出力されません。
以下のようにすると、例外のログがloggerで出力できます。
def main():
logger = getLogger()
handler = FileHandler("./test.log")
logger.addHandler(handler)
daemonize() # double forkした後に標準エラー出力を潰す
try:
do_process() #ここで例外が発生したら、下のexceptでキャッチする
except Exception as e:
logger.exception("Exception {0} occured".format(e))
スレッドを実行する場合
さらに、daemon化してからスレッドを実行する場合、親スレッドのtry-exceptではスレッド内での例外は捕捉されず、例外のスタックトレースはどこにも出力されません。 スレッドのrun()で、例外を捕捉してログを出力する必要があります。
class TestThread(threading.Thread):
_logger = getLogger(__name__)
def run(self):
try:
self._do_process() #ここで例外が発生したら、下のexceptでキャッチする
except Exception as e:
self._logger.exception("Exception {0} occured".format(e))
def main():
logger = getLogger()
handler = FileHandler("./test.log")
logger.addHandler(handler)
daemonize() # double forkした後に標準エラー出力を潰す
try:
thread = TestThread()
thread.start() # thread.run()で例外が発生しても、このtry-exceptでは捕捉できない
except Exception as e:
logger.exception("Exception {0} occured".format(e))
そんなこんなでうじゃうじゃ。