loggingの使い方
まずは基本編。ライブラリ側でログを記述し、
クライアント側でそのログをどのように扱うかを決める。
Library side
まず各ファイルの最初に以下の4行を追加しておく
from logging import getLogger, DEBUG, NullHandler
logger = getLogger(__name__)
logger.addHandler(NullHandler())
logger.setLevel(DEBUG)
これでlogger
に.debug
, .info
等で出力する
logger.info("Enter special block")
NullHandlerが登録してあるのでclientがキャプチャしなかったらこのログは捨てられる。
Client side
ライブラリ側のloggerは__name__
で名前が登録されている。例えばmod.submod1
, mod.submod2
みたいな名前で登録されている。.
で階層化されているのでmod
で参照すると両方のサブモジュールのログを受け取れる。また名前を与えない場合、すべてのログを収集する。
- 全部のログを標準エラー出力(
sys.stderr
)に出す
import logging
logger = logging.getLogger()
logger.addHandler(logging.StreamHandler())
logger.setLevel(logging.DEBUG)
-
mod
モジュールのINFO以上のログをファイル(mod.log
)に出力する
import logging
logger = logging.getLogger("mod")
logger.addHandler(logging.FileHandler("mod.log", mode="w"))
logger.setLevel(logging.INFO)
もちろんこれらのコードをクライアントが実行しやすい関数をライブラリ側で用意することはできる。
JSONで出力する
その後の解析を考えると構造化したログが欲しかったりする。
実はlogger.info
とかに辞書オブジェクトあげることができる:
logger.info({
"key": value,
"homhom": 0,
})
特に設定しない場合、これを普通にprint
した結果が出力されるので見た目にはJSONと変わらないが、
正式なJSONではないのでパースできなくて辛い。
そこで登場するのがpythonjsonloggerである。
これはクライアント側で出力するときにJSONとしてフォーマットし直す。
上のファイルに出力する場合は以下のようにする:
import logging
from pythonjsonlogger import jsonlogger
h = logging.FileHandler("mod.log", mode="w")
h.setFormatter(jsonlogger.JsonFormatter())
logging.getLogger("mod").addHandler(h)
これで行ごとにJSONとして有効なログが出力されます。なのでログを
with open("mod.log") as f:
df = pd.DataFrame([json.loads(l) for l in f])
のように簡単にpandasに流し込める。