Pythonにおけるロギングについて調べてみた
ログを使ってみる。
調査
ログ出力のための print と import logging はやめてほしい - Qiita
16.6. logging — Python 用ロギング機能 — Python 3.6.1 ドキュメント
最小コード
import logging l = logging.getLogger(__name__) handler = logging.StreamHandler() handler.setLevel(logging.DEBUG) l.setLevel(logging.DEBUG) l.addHandler(handler) l.debug('loggingによるメッセージ。StreamHandlerをaddHandler()しないと表示されない。')
ログレベル別出力
l.debug('デバッグ。') l.info('インフォ。') l.warning('ワーニング。') l.error('エラー。') l.critical('クリティカル。')
ログレベル抑制
l.setLevel(logging.ERROR) l.debug('デバッグ。') l.info('インフォ。') l.warning('ワーニング。') l.error('エラー。') l.critical('クリティカル。')
logging.setLevel()
で表示するログレベルを指定する。上記の例は、エラーより低レベルなログは出力しない。エラー、クリティカルのみ表示する。デバッグ、インフォ、ワーニングは非表示。
使い分け
以下のように使い分けをイメージしてみた。
メッセージ通知する相手 | 関数 |
---|---|
エンドユーザ | print() |
開発者 | loggerの各関数 |
print()
の代わりにlogger.info()
が使えるかもしれない。
レベル | 用途 |
---|---|
debug | 変数の値など単体試験レベルの小さな粒度で出力したいとき。 |
info | 機能レベルで意味が理解できるメッセージ。 |
warning | 本来なら正常ルートではないが、自動対処などで正常ルートにしたとき? |
error | 動作が中断されてしまう。動作に必要なデータ不足など。 |
critical | データ破損など? |
調べて考えた
以下、参考にさせていただいた。
ログ設計指針 - Qiita
ログレベルちゃんと使い分けてますか? - OTOBANK Engineering Blog
レベル|通知相手|内容 ——|—-ーーーー|—- trace|開発者|単体テスト的に値を確認したい。テスト後に消していい内容。 debug|開発者|変数値など何でもいい。確認したい最小単位。 info|ユーザ|ユーザにとっての関心事。処理内容や結果が分かるよう通知する。 warning|ユーザ|引数エラーなどユーザ起因で正常ルートでない場合。 error|ユーザ|システムや外部サーバなどユーザ以外で正常ルートでない場合。
info以降はユーザが見てもわかる内容にする。というのが理想だが、それだけでは状況把握や原因特定が正確にできないと思う。
目的
できるだけ迅速に目的を達成できるようなメッセージが欲しい。
異常ルートの場合、ユーザに以下のことを伝えたい。
- 正常に達成できなかった旨
- 何が原因か
- どうすればいいか
できれば、以下も伝えたい。
- どこまでできたか
原因の特定
- 問題がどこにあるのか
- 誰が対処すべきなのか
- エンドユーザはどうすればいいのか
GitHubアップローダ(ツール)で考えてみると、以下のような関係者がいる。
たとえばGitHubのサーバが落ちていてHTTP通信エラーだったとき。エンドユーザやアップローダツール開発者には対処できない。GitHubサーバの回復を待つしか無い。
起動引数の入力ミス、iniファイル設定、~/.ssh/config
、SSH鍵ファイルとそのパスならエンドユーザが対処する。APIリクエスト上限については、2秒間のウェイトを取っているから問題ないはず。
それ以外はツールの問題かもしれない。エンドユーザとしては自らPythonコードを読んで改修するか、開発者など他者に委ねるしかない。
むずかしい切り分け
しかし、たとえば以下のような複雑な状況がありえる。
- ツールでAccessTokenを自動作成したが、サイトで削除してしまった。その後、ツールでアップロードしようとしたが、Tokenが存在しないためAPI実行時にエラーが出た
ツール側での対処が望ましい。存在しないなら既存のTokenをDBから削除し、新規に作成するようにしたい。しかし、存在しない時のエラーコードはGitHubやAPIごとに違うかもしれない。正確な対処はむずかしい。
そもそもエンドユーザはツールがTokenを作ることも知らない可能性がある。Tokenを作ったこともわかりやすい形で表示していないし、Token名も通知していない。アカウントのセッティングページで見慣れないTokenを削除してしまう可能性はある。
所感
たかがログ。しかし、考えるほど厄介。ログ用ライブラリも複雑だし、使い分けも大変そう。
エラーが複雑だと、エラーレベルやメッセージを決めるのも難しくなる。
エラーを減らそうとすると、エラーを回避するための処理を実装せねばならなくなる。
何がエラーで何が仕様なのか。どこまで実装するか。その経緯を把握していないと理解できないようなツールは面倒。
理想を言えばフェイルセーフ、フォールトトレラント設計などを考えて実装したい。しかし現状は「動けばいい」レベル。動作テストすらまともにできていない。