Pythonのloggingモジュールを使っているうちに知見が溜まってきたので記事にします。
設定はfileConfigよりdictConfigで行う
ログレベルやフォーマッタ等の設定を行う際、fileConfig関数とdictConfig関数が利用できる。
dictConfig関数の方が柔軟に設定を行うことができる。
使用例
from logging import getLogger
from logging.config import dictConfig
CONFIG = {
"version": 1,
"disable_existing_loggers": False,
"formatters": {
"default": {
"format": "%(asctime)s %(name)s %(levelname)-5s: %(message)s"
}
},
"handlers": {
"console": {
"class": "logging.StreamHandler",
"formatter": "default",
},
},
"root": {
"level": "INFO",
"handlers": ["console"],
},
}
logger = getLogger(__name__)
if __name__ == '__main__':
dictConfig(CONFIG)
logger.info('hello')
出力項目を追加したりできる(fileConfigには無い機能)
from logging import getLogger, Filter
from logging.config import dictConfig
import flask
class IpAddressFilter(Filter):
"""クライアントのIPアドレスをログレコードに追加"""
def filter(self, record):
record.remote_addr = flask.request.headers.get('REMOTE_ADDR')
return True
CONFIG = {
"version": 1,
"disable_existing_loggers": False,
"formatters": {
"default": {
"format": "%(asctime)s %(name)s %(remote_addr)s %(levelname)-5s: %(message)s"
}
},
"filters": {
"addr": {
"()": IpAddressFilter,
}
}
"handlers": {
"console": {
"class": "logging.StreamHandler",
"formatter": "default",
"filters": ["addr"],
},
},
"root": {
"level": "INFO",
"handlers": ["console"],
},
}
app = flask.Flask(__name__)
dictConfig(CONFIG)
@app.route("/")
def hello_world():
return "<p>Hello, World!</p>"
ロガー設定はモジュールレベルでは行わない
pytestでcaplogを使用してログ出力のテストをする際、テスト対象モジュールをimportするだけでdictConfigやfileConfigによるロガー設定が行われてしまうと、正しくcaplogが動作しない。
dictConfigやfileConfigによるロガー設定はできる限り実際のプログラムとして起動する場合のみ行う。
mainで起動するコマンドラインツールの場合
...
if __name__ == '__main__':
dictConfig(CONFIG)
main()
FlaskやFastAPIなどのアプリケーション変数初期化を行う場合の例
main.py
...
app = create_app()
dictConfig(CONFIG)
# $ export FLASK_APP=main
# $ flask run
app.py
def create_app():
return Flask('app_name')
tests/fixtures/app.py
@fixture
def client():
"""テストクライアント"""
app = create_app()
app.config['TESTING'] = True
with app.test_client() as client:
yield client