Posted at

Python標準のloggingでログをJSON形式で出力する

More than 3 years have passed since last update.


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に流し込める。