2020年12月10日木曜日

flask でデフォルトのエラーログをカスタマイズする方法

概要

Flask で raise された場合デフォルトのエラーログはすべて ERROR レベルで出力されます
またエラーのトレース情報もそのまま表示されます

エラーレベルやトレース情報をカスタマイズする方法を紹介します

環境

  • macOS 10.15.07
  • Python 3.8.5
    • flask 1.1.2

log_execption を実装しログレベルを変更する

Flask クラスを継承して独自の Flask クラスを作成しその中で log_execption メソッドを実装することでエラーログの内容をカスタマイズできます

例えばエラーレベルを WARN にする場合は以下のようにします

import logging
from flask import Flask, request

class MyFlask(Flask):
    def log_exception(self, exc_info):
        self.logger.warn(f"Exception on {request.path} [{request.method}]", exc_info=exc_info)

app = MyFlask(__name__)

@app.route('/error')
def error():
    raise Exception

@app.errorhandler(500)
def abort(error):
    return 'abort'

トレース情報を変更する

exc_info が長いのでエラーが発生した箇所だけログに出したいという場合には以下のようにします

import logging
import traceback
from flask import Flask, request

class MyFlask(Flask):
    def log_exception(self, exc_info):
        tb = exc_info[2]
        tb_str = traceback.format_exception(exc_info[0], exc_info[1], exc_info[2])
        error_line = tb_str[-2].replace("\n", " ")
        self.logger.warn(f"Exception on {request.path} [{request.method}]{error_line}", exc_info=False)

app = MyFlask(__name__)

@app.route('/error')
def error():
    raise Exception

@app.errorhandler(500)
def abort(error):
    return 'abort'

JsonFormatter と組み合わせる

python-json-logger を組み合わせると以下のような感じです

import logging
import traceback
from flask import Flask, request
from pythonjsonlogger import jsonlogger

class MyFlask(Flask):
    def log_exception(self, exc_info):
        tb = exc_info[2]
        tb_str = traceback.format_exception(exc_info[0], exc_info[1], exc_info[2])
        error_line = tb_str[-2].replace("\n", " ")
        self.logger.warn(f"Exception on {request.path} [{request.method}]{error_line}", exc_info=False)

app = MyFlask(__name__)

class CustomJsonFormatter(jsonlogger.JsonFormatter):
    def add_fields(self, log_record, record, message_dict):
        super(CustomJsonFormatter, self).add_fields(log_record, record, message_dict)

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

@app.route('/error')
def error():
    raise Exception

@app.errorhandler(500)
def abort(error):
    return 'abort'

参考サイト

0 件のコメント:

コメントを投稿