やってみる

アウトプットすべく己を導くためのブログ。その試行錯誤すらたれ流す。

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/configSSH鍵ファイルとそのパスならエンドユーザが対処する。APIリクエスト上限については、2秒間のウェイトを取っているから問題ないはず。

それ以外はツールの問題かもしれない。エンドユーザとしては自らPythonコードを読んで改修するか、開発者など他者に委ねるしかない。

むずかしい切り分け

しかし、たとえば以下のような複雑な状況がありえる。

  • ツールでAccessTokenを自動作成したが、サイトで削除してしまった。その後、ツールでアップロードしようとしたが、Tokenが存在しないためAPI実行時にエラーが出た

ツール側での対処が望ましい。存在しないなら既存のTokenをDBから削除し、新規に作成するようにしたい。しかし、存在しない時のエラーコードはGitHubAPIごとに違うかもしれない。正確な対処はむずかしい。

そもそもエンドユーザはツールがTokenを作ることも知らない可能性がある。Tokenを作ったこともわかりやすい形で表示していないし、Token名も通知していない。アカウントのセッティングページで見慣れないTokenを削除してしまう可能性はある。

所感

たかがログ。しかし、考えるほど厄介。ログ用ライブラリも複雑だし、使い分けも大変そう。

エラーが複雑だと、エラーレベルやメッセージを決めるのも難しくなる。

エラーを減らそうとすると、エラーを回避するための処理を実装せねばならなくなる。

何がエラーで何が仕様なのか。どこまで実装するか。その経緯を把握していないと理解できないようなツールは面倒。

理想を言えばフェイルセーフフォールトトレラント設計などを考えて実装したい。しかし現状は「動けばいい」レベル。動作テストすらまともにできていない。