Pythonで例外の詳細情報(スタックトレース)を取得する方法:tracebackモジュールの活用

try-except 文で例外を捕捉し、print(e) でエラー内容を表示するだけでは、大規模なプログラムのデバッグには不十分な場合があります。単純なエラーメッセージだけでは、「具体的にどのファイルの、どの行で、どの関数を経由してエラーが発生したのか」という経路情報(スタックトレース)がわからないためです。

Pythonの標準ライブラリである traceback モジュールを使用すると、このスタックトレースを取得・表示することができます。これは、エラーログをファイルに保存したり、管理者に通知を送ったりする際に不可欠な機能です。

この記事では、traceback モジュールを使って例外の詳細情報を取得する方法について解説します。

目次

print(e) だけでは足りない場合

通常、except Exception as e: として例外を捕捉し print(e) を実行すると、エラーの「種類」と「短いメッセージ」のみが表示されます。

try:
    # リストの範囲外アクセスなどのエラー
    my_list = [10, 20]
    print(my_list[5])
except IndexError as e:
    print(f"エラーが発生しました: {e}")

実行結果:

エラーが発生しました: list index out of range

これだけでは、プログラムのどの部分でこのエラーが発生したのか、即座に特定するのは困難です。特に、関数がいくつも呼び出されている深い階層でエラーが起きた場合には、原因究明に時間がかかります。

traceback モジュールの基本

traceback モジュールを使用すると、Pythonがクラッシュした際に表示されるような詳細なエラー情報を、プログラムを停止させずに取得できます。

traceback.format_exc():文字列として取得

最も汎用的なのが traceback.format_exc() です。これは現在発生している例外のスタックトレースを文字列として返します。文字列なので、ログファイルへの書き込みや、データベースへの保存に適しています。

構文:

import traceback

try:
    # 処理
except Exception:
    # 詳細なエラー情報を文字列で取得
    error_log = traceback.format_exc()
    print(error_log)

実践的なコード例:深い階層のエラー追跡

関数が入れ子になって呼び出されている状況で、最深部でエラーが発生した場合のトレースバックを確認します。

例として、データ分析のパイプライン処理を模したプログラムを作成します。

import traceback

def load_data():
    """データを読み込む関数(ここでエラー発生)"""
    # 意図的に未定義の変数を参照して NameError を発生させる
    return raw_data_buffer

def process_data():
    """データを加工する関数"""
    print("データ加工を開始...")
    load_data()
    print("データ加工を終了")

def main_pipeline():
    """メイン処理"""
    print("--- 処理開始 ---")
    try:
        process_data()
    except Exception:
        # tracebackを使って詳細情報を取得・表示
        print("予期せぬエラーが発生しました。詳細ログを出力します。\n")
        
        # エラー詳細(スタックトレース)を取得
        tb_msg = traceback.format_exc()
        
        # 実際にはここでログファイルへの書き込みなどを行う
        print("---------------- ERROR LOG ----------------")
        print(tb_msg)
        print("-------------------------------------------")
    
    print("--- 処理終了(システムは停止していません) ---")

# 実行
main_pipeline()

実行結果:

--- 処理開始 ---
データ加工を開始...
予期せぬエラーが発生しました。詳細ログを出力します。

---------------- ERROR LOG ----------------
Traceback (most recent call last):
  File "script.py", line 16, in main_pipeline
    process_data()
  File "script.py", line 11, in process_data
    load_data()
  File "script.py", line 6, in load_data
    return raw_data_buffer
NameError: name 'raw_data_buffer' is not defined

-------------------------------------------
--- 処理終了(システムは停止していません) ---

traceback.format_exc() を使用したことで、「main_pipelineprocess_data を呼び、それが load_data を呼び、そこで NameError が発生した」という一連の流れ(トレース)が記録されました。これにより、バグの特定が容易になります。

traceback.print_exc() との使い分け

文字列として取得するのではなく、単に標準エラー出力(コンソール)に表示するだけでよい場合は、traceback.print_exc() を使用すると簡潔に記述できます。

try:
    # エラー処理
    int("文字")
except ValueError:
    # format_exc() で文字列取得して print() するのと同じ結果
    traceback.print_exc()
  • format_exc(): 文字列として取得したい場合(ログ保存、メール送信など)。
  • print_exc(): とりあえず画面に表示したい場合(開発中のデバッグなど)。

まとめ

  • 例外の発生箇所や経路(スタックトレース)を知るには、標準ライブラリの traceback モジュールを使用します。
  • traceback.format_exc() を使うと、スタックトレースを文字列として取得できます。
  • ログファイルへの記録や、エラー監視システムへの通知を行う際には、単なる e ではなく、この詳細情報を記録することが重要です。
よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

この記事を書いた人

私が勉強したこと、実践したこと、してることを書いているブログです。
主に資産運用について書いていたのですが、
最近はプログラミングに興味があるので、今はそればっかりです。

目次