2020年12月5日土曜日

flask で JSON 形式のログを出力する方法

概要

前回リクエスト ID をログに埋め込む方法を紹介しました
今回はそれを JSON で出力してみます
使用するライブラリは python-json-logger です

環境

  • macOS 10.15.7
  • Python 3.8.5
  • flask 1.1.2
  • python-json-logger 2.0.1

インストール

  • pipenv install python-json-logger

サンプルコード

jsonlogger.JsonFormatter をフォーマッタに使います
指定された文字列や dict 情報を JSON に変換して表示します

import logging
from flask import Flask
from pythonjsonlogger import jsonlogger

app = Flask(__name__)

handler = logging.StreamHandler()
formatter = jsonlogger.JsonFormatter()
handler.setFormatter(formatter)
logging.getLogger().addHandler(handler)

@app.route('/')
def hello():
    app.logger.setLevel(logging.INFO)
    app.logger.info("hello")
    return 'ok'

=> {"message": "hello"}

これだと message しか表示されません

日付やログレベルも出力してみる

flask の場合はすでにいくつかの情報が record に設定されているのでそれを参照するだけです
asctime や name, levelname が使えます (参考)

import logging
from flask import Flask
from pythonjsonlogger import jsonlogger

app = Flask(__name__)

handler = logging.StreamHandler()
formatter = jsonlogger.JsonFormatter('%(asctime)s %(name)s %(levelname)s %(message)s')
handler.setFormatter(formatter)
logging.getLogger().addHandler(handler)

@app.route('/')
def hello():
    app.logger.setLevel(logging.INFO)
    app.logger.info("hello")
    return 'ok'

=> {"asctime": "2020-12-03 14:44:39,950", "name": "app", "levelname": "INFO", "message": "hello"}

これで flask でデフォルトで表示されている情報も JSON で表示されるようになれます

カスタムフィールドを追加する

独自のフィールドも追加できます
その場合は jsonlogger.JsonFormatter を継承したクラスを作成して add_fields メソッドを実装します
log_record の dict に key/value を追加していき Formatter を作成する際に追加したフィールドを参照します

import logging
from flask import Flask
from pythonjsonlogger import jsonlogger

app = Flask(__name__)

class CustomJsonFormatter(jsonlogger.JsonFormatter):
    def add_fields(self, log_record, record, message_dict):
        super(CustomJsonFormatter, self).add_fields(log_record, record, message_dict)
        log_record["user"] = "hawksnowlog"

handler = logging.StreamHandler()
formatter = CustomJsonFormatter('%(asctime)s %(name)s %(levelname)s %(message)s %(user)s')
handler.setFormatter(formatter)
logging.getLogger().addHandler(handler)

@app.route('/')
def hello():
    app.logger.setLevel(logging.INFO)
    app.logger.info("hello")
    return 'ok'

参考サイト

0 件のコメント:

コメントを投稿