Change Flask's log settings (dictConfig) to output logs other than the root logger

Introduction

When trying to implement logging in python, I think that you basically build it by referring to the official tutorial.

https://docs.python.org/ja/3/howto/logging.html

logging_test.py


import logging

def main():
    logging.info("it is logging.")

However, as pointed out in this article, the method described in the upper part is not a very appropriate method, and the following notation is recommended. I am.

logger_test.py


from logging import getLogger
logger = getLogger(__name__)

def main():
    logger.info("it is logger.")

Therefore, basically, logging should be implemented by this method, and the log output of the package actually distributed is mainly the one in which the logger name is defined.

Logging in Flask

On the other hand, when implementing logging with Flask, I think that there are many people who implement it by referring to the following sites.

https://msiz07-flask-docs-ja.readthedocs.io/ja/latest/logging.html

At that time, if you implement it with reference to dictConfig,

app.py


from flask import Flask
from logging.config import dictConfig
from src.logging import logging_test, logger_test

dictConfig({
    'version': 1,
    'formatters': {'default': {
        'format': '[%(asctime)s] %(levelname)s in %(module)s: %(message)s',
    }},
    'handlers': {'wsgi': {
        'class': 'logging.StreamHandler',
        'stream': 'ext://flask.logging.wsgi_errors_stream',
        'formatter': 'default'
    }},
    'root': {
        'level': 'INFO',
        'handlers': ['wsgi']
    }
})

app = Flask(__name__)

@app.route('/')
def hello_world():
    logging_test.main()
    logger_test.main()
    return 'Hello, World!'

if __name__ == "__main__":
    app.run(debug=True)

The logger log will not be output.

[2020-11-12 09:47:05,506] INFO in logging_test: it is logging.
[2020-11-12 09:47:05,506] INFO in _internal: 127.0.0.1 - - [12/Nov/2020 09:47:05] "GET / HTTP/1.1" 200 -

This is because defining the logger name with getLogger makes it no longer a root logger. Therefore, in order to output as Flask log, put the logger you want to output to the loggers of dictConfig. Need to be added.

    'loggers': {'src': {
        'level': 'INFO'
    }},

By doing this, you will be able to output the logger under src.

[2020-11-12 10:02:17,987] INFO in logging_test: it is logging.
[2020-11-12 10:02:17,987] INFO in logger_test: it is logger.
[2020-11-12 10:02:17,988] INFO in _internal: 127.0.0.1 - - [12/Nov/2020 10:02:17] "GET / HTTP/1.1" 200 -

You can also specify individual handlers to output the log. In that case, the log will be output twice, so set propagate to False. And you can prevent it.

    'loggers': {'src': {
        'level': 'INFO',
        'handlers': ['wsgi'],
        'propagate': False
    }},

Output the log of the imported package

By applying this, you can also output the logger of the imported package. For example, if you want to output the logger of Flask-OAuthlib, add the following settings to loggers.

    'flask_oauthlib': {
        'level': 'DEBUG'
    }

By doing this, you will be able to check the log output of the package as before.

Finally

I've spent a little time trying to find out, so I'll leave it as a memorandum.

Recommended Posts

Change Flask's log settings (dictConfig) to output logs other than the root logger
Setting to output the log of cron execution
Change the standard output destination to a file in Python
Change the log retention period of CloudWatch Logs in Lambda
I tried to output the access log to the server using Node.js