skip to Main Content

I’d like to use logging in my Flask app by simply calling logging.getLogger('myapi') in each of the files where I need to log.

There should be a single place to define the handler and format for this “global” application logger. This works, but Flask is also continually logging its own logs in the default format. These logs only exist when I import the library fbprophet. I would like to prevent Flask from logging these extra, unformatted, duplicate logs.

(Flask also has a werkzeug logger, which is fine and can stay.)

Code:

import sys
import logging
import fbprophet
from flask import Flask, jsonify
from werkzeug.serving import run_simple

# Set up my custom global logger
log = logging.getLogger('myapi')
handler = logging.StreamHandler(sys.stdout)
handler.setFormatter(logging.Formatter('*** %(asctime)s %(levelname)s %(message)s'))
log.addHandler(handler)
log.setLevel(logging.DEBUG)

def create_app(config={}):
    ''' Application factory to create and configure the app '''
    app = Flask('myapi', instance_relative_config=False)
    app.config.from_mapping(config)

    log.info('TEST INFO')
    log.debug('TEST DEBUG')

    @app.route('/health')
    def health():
        log.info('Health OK')
        return 'OK'

    return app

if __name__ == '__main__':
    dev_config = {'SECRET_KEY': 'dev', 'DEBUG': False}
    app = create_app(dev_config)
    run_simple('localhost', 5000, app)

Output:

I’m expecting to see logs prefixed with ***. The ones starting with LEVEL only appear when I import facebook prophet.

* Serving Flask app "main.py" (lazy loading)
* Environment: development
* Debug mode: on
* Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
* Restarting with stat
* Debugger is active!
*** 2019-06-05 14:17:56,702 INFO TEST INFO          # good log
INFO:myapi:TEST INFO                                # bad dupe log
*** 2019-06-05 14:17:56,702 DEBUG TEST DEBUG
DEBUG:myapi:TEST DEBUG
*** 2019-06-05 14:17:56,703 INFO TEST INFO
INFO:myapi:TEST INFO
*** 2019-06-05 14:17:56,703 DEBUG TEST DEBUG
DEBUG:myapi:TEST DEBUG
*** 2019-06-05 14:18:10,405 INFO Health OK
INFO:myapi:Health OK
127.0.0.1 - - [05/Jun/2019 14:18:10] "GET /health HTTP/1.1" 200 -               # good werkzeug api log
INFO:werkzeug:127.0.0.1 - - [05/Jun/2019 14:18:10] "GET /health HTTP/1.1" 200 - # bad dupe log

More explanation:

I’ve tried setting the app’s logger too, but I don’t want to have to call current_app.logger from other modules.

I tried disabling Flask’s logger with logging.getLogger('flask.app').handlers.clear() but this also doesn’t work.

When importing fbprophet, I get the below console errors (from prophet):

ERROR:fbprophet:Importing matplotlib failed. Plotting will not work.
ERROR:fbprophet:Importing matplotlib failed. Plotting will not work.
*** 2019-06-05 14:29:06,488 INFO TEST INFO
INFO:myapi:TEST INFO

I thought this could be causing the issue, so I fixed the errors following this. But Flask is still logging the extra logs.

import plotly
import matplotlib as mpl
mpl.use('TkAgg')
import fbprophet

Summary:

Looking for formatted global logging in Flask with no duplicate logs. I just need my global logging.getLogger('myapi') and the werkzeug API logs.

2

Answers


  1. You can search through all the registered loggers and change their settings as needed. It sounds like fbprophet is probably setting its own logger instance, so hopefully it will get set to the level you want if you do something like this:

    for logger_name in logging.root.manager.loggerDict:
        print(f"found a logger:{logger_name}")
        logger = logging.getLogger(logger_name)
        logger.setLevel(logging.ERROR)
    
        if logger_name == 'myapi':
            logger.setLevel(logging.INFO)
    
    Login or Signup to reply.
  2. I’ve had the same problem and spent hours to resolve it. Actually it’s not even related to Flask (I figured this out after few hours).

    Even in a simple script you’ll have the duplicated log in your handler.

    The only working solution seems to be to add: logger.propagate = False in your own handler. This will prevent the log to be passed to handlers of higher level (ancestor) loggers i.e loggers created by Prophet (even if I dont see where this hierarchy resides exactly).

    Found in this answer: https://stackoverflow.com/a/55877763/3615718

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search