エラーが発生した時に詳細を残したい

エラーが起こった場合に、それがどこで起こったのかを把握するための方法で、2つご紹介します。

実際には残し方自体は別途お考えください。といいますのも、ログファイルに記録するというのが一番ありがちですが、その他にはDBに記録したり、場合によっては外部に通知するためにHTTPリクエストを送信するなど、様々な利用方法が考えられます。ここでは、捕捉した情報を単純にprint()で出力するという例になっています。

まず1つ目はどのソースコードの何行目でどんなエラーが起こったかについて記録するものです。実際には2つ目を用いることの方が多いかも知れませんが、どのオブジェクトのどの変数を見れば、どんな情報が入っているのかというのは、知識として得ておいても良いかと思います。

もう一つは、try-exceptでエラーハンドリングしなかった場合、ずらずらとコンソールに表示されているエラー情報で、a.pyの54行目でx = xxx()が実行されて、b.pyの31行目でy = yyy()が実行されて・・・c.pyの40行目でxxエラーという情報です。この情報をスタックトレースといいます。

Java等でスタックトレースと言えば、文字通りスタックされているかのごとく上に積まれているのですが、Pythonの場合は出てくる順序が逆で、下に向かって進んでいって最後にエラーで終わるという流れです。

ちなみに、スタックトレースという言葉は、Pythonのマニュアルにも登場しますが、そのために用意されているオブジェクトがトレースバックという名前なので、実際に扱うのはtracebackになります。

サンプルコード1

exception_info.py

#!/usr/bin/env python3.8

import sys
import linecache

def exception_info():
    exc_type, exc_obj, tb = sys.exc_info()
    f = tb.tb_frame
    lineno = tb.tb_lineno
    filename = f.f_code.co_filename
    linecache.checkcache(filename)
    line = linecache.getline(filename, lineno, f.f_globals)
    return 'EXCEPTION IN ({}, LINE {} "{}"): {}'.format(filename, lineno, line.strip(), exc_obj)


try:
    a = "a"
    x = int(a)

except Exception as ex:
    print(exception_info())

実行

$ python exception_info.py 
EXCEPTION IN (exception_info.py, LINE 19 "x = int(a)"): invalid literal for int() with base 10: 'a'
$ 

問題が発生時に実行していたファイル名と行番号、それから問題となった文、最後にエラーの内容です。

見た目や順序などはお好みのものに変えるとしても、このくらいの情報があればかなりエラーの調査が進むのではないでしょうか。

サンプルコード2

#!/usr/bin/env python3.8

import traceback


def str_to_int(arg):
    i = int(arg)
    return i


try:
    a = "a"
    x = str_to_int(a)

except Exception:
    print(traceback.format_exc())

実行

(LearningPython) MacBookPro:01.exception_info $ python exception_info2.py
Traceback (most recent call last):
  File "exception_info2.py", line 14, in 
    x = str_to_int(a)
  File "exception_info2.py", line 8, in str_to_int
    i = int(arg)
ValueError: invalid literal for int() with base 10: 'a'

(LearningPython) MacBookPro:01.exception_info $

無事取得できましたね。仮に本番環境であったとしても、この手の情報は出来れば入手可能にしておきたいですね。