logging モジュールを使った Python logging、Python の5つのログレベル、Python のエラー処理、よくある Python のエラーの種類を説明します。最後のセクションでは、logbrew-sdk 0.1.29 を使って同じログとクラッシュを LogBrew に送信します。どの例も Python 3.13 で実行しました。出力のブロックはすべて実際の出力です。
Flask アプリケーションの場合は、代わりに Flask のログを使ってください。同じログ設定にリクエストのトレースが加わります。
Python logging で最初のログを出力する
このファイルをapp.py として保存します。logging.basicConfig() は、プログラムのエントリーポイントで1回だけ呼び出します。各モジュールでは名前付きのロガーを取得します。
python3 app.py を実行します。出力は標準エラー出力に送られます。
INFO なので、debug のレコードは表示されません。logger.exception() は ERROR レベルでログを記録し、トレースバックを追加します。このメソッドは except ブロックの中だけで呼び出してください。
値は "payment retry %d of %d", 2, 3 のように引数として渡します。Python は、ハンドラーがレコードを受け付けたときにだけメッセージを組み立てます。メッセージのテンプレートはどの再試行でも同じなので、そのテンプレートで検索できます。
Python のログレベル
ロガーがレコードを送るのは、レコードのレベルがロガーのレベル以上のときだけです。ハンドラーには、それより高い2つ目のレベルを設定できます。
ルートロガーの初期レベルは
WARNING です。新しいロガーのレベルは NOTSET(0)で、親のレベルを使います。本番環境では INFO を設定します。DEBUG は開発中か、短時間の診断のときだけ使います。
ロガー、ハンドラー、フォーマッター
- ロガーは呼び出しを受け取ります。ロガー名がモジュールのパスと一致するように、
logging.getLogger(__name__)を使います。 - ハンドラーは、コンソール、ファイル、LogBrew などの送信先にレコードを送ります。
- フォーマッターは、レコードをテキストに変換します。
logging.NullHandler() だけを追加します。ハンドラーとレベルは、アプリケーションが1回だけ設定します。設定が大きい場合は logging.config.dictConfig() を使います。
Python のエラー処理
処理できる例外のうち、最も具体的なものをキャッチします。成功したときだけ実行するコードにはelse を、常に実行するコードには finally を使います。元の原因を残すには raise ... from error を使います。
このファイルを orders.py として保存します。
- 例外は、処理する場所で1回だけログに記録します。各レイヤーでログに記録してから再送出しないでください。レイヤーごとに重複したレコードが増えます。
except Exception: passと書かないでください。エラーを無視する場合は、理由を添えてWARNING以上のレベルでログに記録します。BaseExceptionではなくExceptionをキャッチします。BaseExceptionは、意図的にプログラムを止めるKeyboardInterruptとSystemExitもキャッチします。- 呼び出し側で処理する必要があるエラーには、
OrderErrorのように独自の例外クラスを定義します。
複数のエラーを報告する
Python 3.11 以降ではExceptionGroup を送出できます。1回のチェックで複数の問題が見つかったときに使います。種類ごとに except* で処理します。
よくある Python のエラーの種類
プログラムで処理できる組み込みのエラーは、すべてException を継承しています。次の表に、よく見る Python のエラーと、それぞれで最初に確認することをまとめます。
KeyboardInterrupt と SystemExit は、Exception ではなく BaseException を継承しています。これらはコードのエラーではありません。
Python のログを LogBrew に送信する
LogBrewLoggingHandler は標準のロギングハンドラーです。受け付けた各レコードを LogBrew に送信します。コンソールのハンドラーはそのまま変わりません。
1
プロジェクトのキーを作成する
CLI でサインインします。プロジェクトを作成し、その取り込みキーを所有者だけが読めるファイルに保存します。CLI はキーを表示しません。本番環境では、利用しているプラットフォームのシークレット管理機能を使ってください。
2
SDK をインストールする
アプリケーションの仮想環境を有効化します。次に、パッケージをインストールします。このパッケージには Python 3.10 以降が必要です。
3
キーとデプロイの識別情報を設定する
4
ハンドラーを追加する
このファイルを
worker.py として保存します。クライアントを作成する前に logging.basicConfig() を呼び出します。クライアントはルートロガーにハンドラーを追加します。ルートロガーにハンドラーがすでにあると、basicConfig() は何もしません。HttpTransport() は、最初のイベントから1秒後、またはイベントが50件たまった時点で、バックグラウンドでイベントを送信します。client.shutdown() は残りのイベントを送信し、クライアントを閉じます。5
プログラムを実行する
extra={...} のプリミティブ値はメタデータになります。2件目のイベントでは、exceptionName が KeyError、exceptionMessage が 'seats' です。トレースバックの全文を送信するには、include_exception_text=True を指定してハンドラーを作成します。6
ログを読み取って確認する
LogBrew に送るレコードを選ぶ
送るレコードを減らすには、ハンドラーに専用のレベルを設定します。コンソールには引き続きINFO 以上が出力されます。
Python のクラッシュを課題として報告する
install_process_error_capture(client) は、スクリプト、ワーカー、起動コード、スレッドで捕捉されなかった例外を報告します。各クラッシュは1件の課題になり、例外の型、メッセージ、スタックフレーム、例外チェーンの原因を含みます。Python は、これまでどおりトレースバックを出力して終了します。
このファイルを startup.py として保存し、実行します。
FileNotFoundError、レベルが critical、メカニズムが python.excepthook の課題を受け取ります。そのフレームには、ファイル名、行、関数が含まれます。フルパスは含まれません。スレッド内のクラッシュのレベルは error です。Python が終了する前に、SDK は配信を最大2秒待ちます。
トラブルシューティング
Web アプリケーションについては Flask のログを参照してください。ログ形式を選ぶには構造化ログを参照してください。ほかのランタイムについては SDK 連携を参照してください。
