Flask + sqlalchemy advanced logging

老子叫甜甜 提交于 2019-12-11 04:26:51

问题


I found a few other posts on this but none that worked for me yet so I wanted to reach out and see if anyone could explain how to properly get / redirect / set handlers on some of the loggers present in Flask / Werkzeurg / sqlalchemy.

Research prior that could not answer my question:

https://github.com/pallets/flask/issues/1359

http://flask.pocoo.org/docs/dev/logging/

https://gist.github.com/ibeex/3257877

My configurations:

main.py

    ...

    def init_app():
    """ Runs prior to app launching, contains initialization code """

    # set logging level
    if not os.path.exists(settings.LOG_DIR):
        os.makedirs(settings.LOG_DIR)

    # default level
    log_level = logging.CRITICAL

    if settings.ENV == 'DEV':
        log_level = logging.DEBUG
    elif settings.ENV == 'TEST':
        log_level = logging.WARNING
    elif settings.ENV == 'PROD':
        log_level = logging.ERROR

    log_formatter = logging.Formatter("[%(asctime)s] {%(pathname)s:%(lineno)d} %(levelname)s - %(message)s")
    api_logger = logging.getLogger()
    api_handler = TimedRotatingFileHandler(
            settings.API_LOG_FILE,
            when='midnight',
            backupCount=10
        )
    api_handler.setLevel(log_level)
    api_handler.setFormatter(log_formatter)
    api_logger.addHandler(api_handler)
    logging.getLogger('werkzeug').addHandler(api_handler)


    db_logger = logging.getLogger('sqlalchemy')
    db_handler = TimedRotatingFileHandler(
            settings.DB_LOG_FILE,
            when='midnight',
            backupCount=10
        )
    db_handler.setLevel(log_level)
    db_handler.setFormatter(log_formatter)
    db_logger.addHandler(db_handler)
    logging.getLogger('sqlalchemy.engine').addHandler(db_handler)
    logging.getLogger('sqlalchemy.dialects').addHandler(db_handler)
    logging.getLogger('sqlalchemy.pool').addHandler(db_handler)
    logging.getLogger('sqlalchemy.orm').addHandler(db_handler)



# add endpoints

...


if __name__ == '__main__':
    init_app()
    app.run(host='0.0.0.0', port=7777)

I tried grabbing and changes settings on the loggers a few different ways but I still end up with the werkzeug debug outputting to console and not my logs, I can see the logs are being created but it doesn't look like the loggers are actually outputting to them:

api.log (formatter wrote to it)

2018-02-15 12:03:03,944] {/usr/local/lib/python3.5/dist-packages/werkzeug/_internal.py:88} WARNING -  * Debugger is active!

db.log (empty)

Any insight on this would be much appreciated!

UPDATE

I was able to get the werkzeug logger working using the long hand version, it seems the shorthand function calls shown were returning null objects. The sqlalchemy logger is still outputting to console though.. Could the engine configuration be overriding my filehandler?

main.py

...

# close current file handlers
for handler in copy(logging.getLogger().handlers):
    logging.getLogger().removeHandler(handler)
    handler.close()
for handler in copy(logging.getLogger('werkzeug').handlers):
    logging.getLogger('werkzeug').removeHandler(handler)
    handler.close()
for handler in copy(logging.getLogger('sqlalchemy.engine').handlers):
    logging.getLogger('sqlalchemy.engine').removeHandler(handler)
    handler.close()
for handler in copy(logging.getLogger('sqlalchemy.dialects').handlers):
    logging.getLogger('sqlalchemy.dialects').removeHandler(handler)
    handler.close()
for handler in copy(logging.getLogger('sqlalchemy.pool').handlers):
    logging.getLogger('sqlalchemy.pool').removeHandler(handler)
    handler.close()
for handler in copy(logging.getLogger('sqlalchemy.orm').handlers):
    logging.getLogger('sqlalchemy.orm').removeHandler(handler)
    handler.close()


# create our own custom handlers
log_formatter = logging.Formatter("[%(asctime)s] {%(pathname)s:%(lineno)d} %(levelname)s - %(message)s")
api_handler = TimedRotatingFileHandler(
        settings.API_LOG_FILE,
        when='midnight',
        backupCount=10
    )
api_handler.setLevel(log_level)
api_handler.setFormatter(log_formatter)
logging.getLogger().setLevel(log_level)
logging.getLogger().addHandler(api_handler)
logging.getLogger('werkzeug').setLevel(log_level)
logging.getLogger('werkzeug').addHandler(api_handler)


db_handler = TimedRotatingFileHandler(
        settings.DB_LOG_FILE,
        when='midnight',
        backupCount=10
    )
db_handler.setLevel(log_level)
db_handler.setFormatter(log_formatter)
logging.getLogger('sqlalchemy.engine').addHandler(db_handler)
logging.getLogger('sqlalchemy.engine').setLevel(log_level)
logging.getLogger('sqlalchemy.dialects').addHandler(db_handler)
logging.getLogger('sqlalchemy.dialects').setLevel(log_level)
logging.getLogger('sqlalchemy.pool').addHandler(db_handler)
logging.getLogger('sqlalchemy.pool').setLevel(log_level)
logging.getLogger('sqlalchemy.orm').addHandler(db_handler)
logging.getLogger('sqlalchemy.orm').setLevel(log_level)

database.py

...
engine = create_engine(getDBURI(), echo="debug", echo_pool=True, pool_recycle=10)

ANSWER

For future reference if anyone runs into this issue, sqlalchemy engine configuration echo=True|'debug' will OVERRIDE your loggers. Fixed the issue by changing my engine configuration to:

engine = create_engine(getDBURI(), echo_pool=True, pool_recycle=10)

And then everything worked like a charm. Cheers! :D


回答1:


as i understand it your file based log configuration for werkzeug is actually working => it outputs into api.log

The db log handler is also working (file gets created etc.) but there is no output. This is probably due to the loglevel of those loggers beeing on Error by default. You need to set them manually on a lower level like this:

logging.getLogger('sqlalchemy.engine').setLevel(logging.DEBUG)
logging.getLogger('sqlalchemy.dialects').setLevel(logging.DEBUG)
logging.getLogger('sqlalchemy.pool').setLevel(logging.DEBUG)
logging.getLogger('sqlalchemy.orm').setLevel(logging.DEBUG)

That werkzeug is still outputting to console is probably because there is allways a root logger defined. Before you add your new handlers you should do the following to remove all log handlers:

    for handler in copy(logging.getLogger().handlers):
        logging.getLogger().removeHandler(handler)
        handler.close()  # clean up used file handles

Then you can also assign your app log handler as the root log handler with

logging.getLogger().addHandler(api_handler)

If its not the root logger but just the werkzeug logger which has a default console logger defined you can also just remove all handlers from the werkzeug logger before adding yours like this:

    for handler in copy(logging.getLogger('werkzeug').handlers):
        logging.getLogger('werkzeug').removeHandler(handler)
        handler.close()  # clean up used file handles
    logging.getLogger('werkzeug').addHandler(api_handler)


来源:https://stackoverflow.com/questions/48812971/flask-sqlalchemy-advanced-logging

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!