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
You can search through all the registered loggers and change their settings as needed. It sounds like
fbprophet
is probably setting its ownlogger
instance, so hopefully it will get set to the level you want if you do something like this: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