2023-7-24

python-json-loggerを導入した

機械学習

python

自動取引

作っている株の自動取引基盤でログを分析するにあたって、json形式のログを扱えるようにしたくなった。 特にCloudWatchInsightでログを漁るときに、ログにタグのようなものを付けられると使い勝手が良さそうだということで環境を整備した。 1からloggingライブラリのFormatterを自作するのは面倒くさそうなので、省ける手間はライブラリを使って可能な限り省きたい。 いい感じのpython-json-loggerというライブラリが見つかったのでこれを使った。

python-json-logger

loggingのFormatterとして提供されているので、Handlerに登録すれば使える。 以下の2つの方法で出力した内容を指定することで、自由に構造化されたログを出力できるようになる。

JsonFormatterの初期化時にFormatを指定する

loggingのFormatterは第一引数でログの出力形式を指定できるが、 python-json-loggerもその形式に倣った方法で出力する情報を指定できる。 コンストラクタの第一引数にformat文字列を渡すことで構造化ログに含めるLogRecordの情報を変更できる。 使えるattributeはLogRecordに定義されているものと同一。

python
Copied!
import logging
import sys
from pythonjsonlogger import jsonlogger


def setup_logging(log_level=logging.INFO):
    handlers = []
    formatter = jsonlogger.JsonFormatter("%(levelname)%(exc_info)%(message)")
    sh = logging.StreamHandler(sys.stdout)
    sh.setFormatter(formatter)
    sh.setLevel(log_level)
    handlers.append(sh)
    logging.basicConfig(level=log_level, handlers=handlers, force=True)


setup_logging()
logger = logging.getLogger()
logger.info("Hello")
>> {"levelname": "INFO", "exc_info": null, "message": "Hello"}

ログする際にextra引数に情報を渡す

上の方法はLogRecord自体が持っている情報を出力する方法だったが、こちらはログする際に任意の情報を付加する方法。 logging.infoやlogging.errorでログを残す際にキーワード引数extraで追加の情報を渡してあげる。(extra引数自体はloggingの標準機能) こんな感じで辞書のルート階層?にextraで指定した情報が追加される。

python
Copied!
# ほとんど上のコードと同じ
import logging
import sys
from pythonjsonlogger import jsonlogger


def setup_logging(log_level=logging.INFO):
    handlers = []
    formatter = jsonlogger.JsonFormatter("%(levelname)%(exc_info)%(message)")
    sh = logging.StreamHandler(sys.stdout)
    sh.setFormatter(formatter)
    sh.setLevel(log_level)
    handlers.append(sh)
    logging.basicConfig(level=log_level, handlers=handlers, force=True)


setup_logging()
logger = logging.getLogger()

# extraにログに出力したい情報を追記
logger.info("Hello", extra={"target": "World"})
>> {"levelname": "INFO", "exc_info": null, "message": "Hello", "target": "World"}

おわりに

思惑通りCloudWatchに構造化ログを出力できた。 CloudWatch Insightなどで集計処理などが非常に書きやすくなるので便利。