ログの記録と解析 | ロギング | Python本格超入門

スポンサーリンク
スポンサーリンク
amazon
スマイルSALE
--:--:--
ad. 価格範囲を指定して商品を探せます

ログの記録と解析

システム開発やアプリケーションの運用において、プログラムが「いつ」「どこで」「どのような処理を行ったか」、そして「どんなエラーが起きたか」を時系列で記録する仕組みをロギング(Logging)と呼びます。

開発中のデバッグ目的だけでなく、本番環境で予期せぬ不具合が発生した際に、原因を特定してトラブルシューティングを行うための唯一の手がかりとなるため、実務において極めて重要な技術です。Pythonでは標準ライブラリの logging モジュール を使うことで、高度なログ管理を簡単に実装できます。

ロギングの基本的な使い方

Pythonでログを出力する最もシンプルな実装例です。logging.basicConfig() を使って、出力するログの基準や見た目を一括で設定します。

import logging

# ログの基本設定
# level: DEBUG以上のすべてのログを出力対象にする
# format: 「日時 - ログの重要度 - メッセージ」の形式で表示するよう指定
logging.basicConfig(
    level=logging.DEBUG, 
    format='%(asctime)s - %(levelname)s - %(message)s'
)

# さまざまな重要度のログを記録
logging.debug('【DEBUG】変数の値を確認: x = 10')
logging.info('【INFO】ユーザーのログイン処理が完了しました')
logging.warning('【WARNING】ディスク容量が残り20%未満です')
logging.error('【ERROR】ファイルの読み込みに失敗しました')
logging.critical('【CRITICAL】データベースに接続できません。システムを停止します')

ログレベル(重要度)の仕組みと適切な使い分け

logging モジュールには5段階のログレベル(重要度)が用意されています。開発時や運用時にログが溢れてしまわないよう、状況に応じて適切なレベルを使い分ける必要があります。

ログレベル 数値(優先度) システム上の意味 実務での具体的なユースケース
DEBUG 10 詳細なデバッグ情報 開発中に、関数の引数の値やループの通過回数など、細かい挙動を追跡したいとき。
INFO 20 通常の動作・進行情報 「サーバーが起動した」「バッチ処理が正常に終了した」など、順調に進んでいる記録。
WARNING 30 想定外だが、動作は継続できる警告 「古い関数(非推奨)が使われた」「設定ファイルがないのでデフォルト値で代用した」とき。
ERROR 40 問題が発生し、一部の処理が失敗した状態 「特定のデータ処理で例外が発生した」など、機能は失敗したがシステム自体は稼働し続けられるとき。
CRITICAL 50 致命的なエラー、即時対応が必要な状態 「メモリ不足でクラッシュした」「メインのDBに繋がらない」など、アプリの継続が不可能なとき。

basicConfig(level=logging.WARNING) のように設定すると、それより数値(優先度)が低い DEBUGINFO のログは自動的に無視され、画面やファイルに出力されなくなります。「開発環境では DEBUG、本番環境では INFO もしくは WARNING」 と切り替えるのが実務の標準です。

ログをファイルへ保存する(永続化)

画面(標準出力)に表示されたログは、コンソールを閉じると消えてしまいます。後から解析できるように、ログをファイルとして自動保存(永続化)するには、basicConfigfilename 引数 を指定します。

import logging

# filename を指定すると、画面ではなく指定ファイルに追記(Append)されるようになります
# encoding='utf-8' を指定することで、日本語の文字化けを防ぎます
logging.basicConfig(
    filename='app.log', 
    filemode='a', # 'a'は追記、'w'は毎回上書き
    encoding='utf-8',
    level=logging.INFO, 
    format='%(asctime)s - %(levelname)s - %(message)s'
)

logging.info('アプリケーションの実行を開始しました。')
logging.warning('外部APIの応答が遅延しています。')

【注意】実務での注意点(basicConfigの罠)
logging.basicConfig() は、プログラム内で「最初に呼び出された1回だけ」しか効果がありません。すでに別のライブラリなどでログ設定が走った後に呼び出しても、設定が完全に無視されてしまいます。そのため、ログの設定は必ずメインプログラムの最上部で行う必要があります。

エラー発生時の「スタックトレース」をログに残す方法

try-except 構文でエラー(例外)をキャッチした際、単に「エラーが起きました」とメッセージを残すだけでは不十分です。logging.error(..., exc_info=True) または logging.exception(...) を使用すると、エラーがプログラムの何行目で発生したかという詳細な形跡(スタックトレース)を丸ごとログに書き出すことができます。

import logging

logging.basicConfig(level=logging.ERROR, format='%(asctime)s - %(levelname)s - %(message)s')

try:
    # 意図的にゼロ除算エラーを発生させる
    result = 10 / 0
except ZeroDivisionError as e:
    # logging.exception を使うと、自動的に詳細なエラーの裏付け(トレースバック)が記録されます
    logging.exception("計算処理中に予期せぬエラーが発生しました。")

これを実行すると、ファイルやコンソールには以下のような極めて有益な解析データが書き出されます。

2026-07-10 11:35:00,000 - ERROR - 計算処理中に予期せぬエラーが発生しました。
Traceback (most recent call last):
  File "script.py", line 6, in <module>
    result = 10 / 0
ZeroDivisionError: division by zero

実践的なログ解析のステップ

大量に出力されたログファイルから問題の根本原因を特定(トラブルシューティング)する際の標準的な手順です。

  1. 致命的なエラーの抽出(フィルタリング):まずはログファイルを ERRORCRITICAL というキーワードで検索(Linux環境であれば grep コマンド等を使用)し、どこで不具合が起きたかをピンポイントで特定します。
  2. 文脈(コンテキスト)の解析:エラーが見つかったら、その直前の時間帯(asctime)に出力されている INFODEBUG のログを読み込みます。「エラーが起きる直前に、ユーザーがどんなボタンを押したか、どんなデータを入力したか」という前後の文脈を追うことで、再現手順が見えてきます。
  3. 時間帯ごとの発生頻度確認:特定の時間帯に一斉にエラーや警告が多発している場合、プログラムのバグではなく、「その時間にアクセスが集中してサーバーのメモリが限界に達した」「連携している外部システムがメンテナンスで落ちていた」といったインフラ・環境側の原因を導き出すことができます。

まとめ

  • print文の代わりにログを使うprint() での動作確認は本番環境に残せませんが、logging であればレベル管理によって、本番環境のパフォーマンスを落とさずに安全な運用監視が行えます。
  • 状況に応じたレベル分けの徹底:デバッグ、通常運用、システム異常を DEBUG / INFO / ERROR と正しく分類して出力することで、ノイズの少ない綺麗なログ設計が実現します。
  • 不具合時は logging.exception で証拠を残す:例外処理(try-except)と組み合わせる際は、エラーメッセージだけでなく Traceback 情報まで確実に記録させることで、デバッグ効率が劇的に向上します。

実務でより大規模なアプリケーション(DjangoやFastAPIなどのWebアプリなど)を構築する際は、ログを日付ごとに自動分割する「ローテーティング(RotatingFileHandler)」などの高度なハンドラー機能を取り入れることで、ファイル容量の肥大化を防ぎつつ、さらに堅牢なシステムログ基盤を構築できるようになります。