訂正(一部ダメでした。。)
record.clientip = request.remote_addr
上記を設定すると、特定条件(SQLAlchemyでSQLALCHEMY_ECHOを設定した場合など)下で下記エラーが発生してしまいました。
RuntimeError: Working outside of request context.
appインスタンス生成前にrequestコンテキストにアクセスしてるからと思われます。
とりあえずメモ
まえがき
趣味の小物アプリでflaskを使った際に調べたこと。
nginxのログと照らし合わせるため、flaskのログにIPアドレスを出したいと思った。
(本当はrequest_id的なもので透過的に見れるといいんですが…)
pythonのloggerではフォーマット指定の際、extraフィールドに任意の識別子を含めることが出来る。
extraパラメータは実際のログ出力時に毎回指定する事も出来るが、filtersを使ってミドルウェア的に挟むことが出来る。
環境
Python 3.10.10
Flask==2.2.2
ソース抜粋
common/logger.py
from logging import Filter
from logging.config import dictConfig
from flask import request
class ExtraFilter(Filter):
def filter(self, record):
# flaskからremote_addrを取得しclientipとして設定
record.clientip = request.remote_addr
return True
def init():
dictConfig({
'version': 1,
'formatters': {
'default': {
# ↓↓↓↓↓↓ フォーマットに独自フィールドのclientipを入れた
'format': '[%(asctime)s][%(levelname)s][%(clientip)s][%(module)s] %(message)s',
}
},
'filters': {
'extra': {
# ↓↓↓↓↓↓ 上で定義したフィルタクラスをフルパスで
'()': 'common.logger.ExtraFilter',
},
},
'handlers': {
"fileHandler": {
"class": "logging.FileHandler",
"formatter": "default",
# ↓↓↓↓↓↓ ハンドラと紐づけ
'filters': ['extra'],
"level": 'DEBUG',
"filename": f"/logs/flask.log",
"encoding": "utf-8"
}
},
'root': {
'level': 'DEBUG',
'handlers': ['fileHandler']
}
})
app.py
from flask import Flask
import common.logger
def create_app():
# ↓↓↓↓↓↓ 初期化
common.logger.init()
app = Flask(__name__)
return app
app = create_app()
出力結果例
[2023-02-14 21:49:52,441][INFO][172.26.0.1][login] test
参考