Logging

Flask uses standard Python logging. Messages about your Flaskapplication are logged with app.logger,which takes the same name as app.name. Thislogger can also be used to log your own messages.

  1. @app.route('/login', methods=['POST'])def login(): user = get_user(request.form['username'])

  2. if user.check_password(request.form['password']):
  3.     login_user(user)
  4.     app.logger.info('%s logged in successfully', user.username)
  5.     return redirect(url_for('index'))
  6. else:
  7.     app.logger.info('%s failed to log in', user.username)
  8.     abort(401)

Basic Configuration

When you want to configure logging for your project, you should do it as soonas possible when the program starts. If app.loggeris accessed before logging is configured, it will add a default handler. Ifpossible, configure logging before creating the application object.

This example uses dictConfig() to create a loggingconfiguration similar to Flask’s default, except for all logs:

  1. from logging.config import dictConfig
  2.  
  3. dictConfig({
  4. 'version': 1,
  5. 'formatters': {'default': {
  6. 'format': '[%(asctime)s] %(levelname)s in %(module)s: %(message)s',
  7. }},
  8. 'handlers': {'wsgi': {
  9. 'class': 'logging.StreamHandler',
  10. 'stream': 'ext://flask.logging.wsgi_errors_stream',
  11. 'formatter': 'default'
  12. }},
  13. 'root': {
  14. 'level': 'INFO',
  15. 'handlers': ['wsgi']
  16. }
  17. })
  18.  
  19. app = Flask(__name__)

Default Configuration

If you do not configure logging yourself, Flask will add aStreamHandler to app.loggerautomatically. During requests, it will write to the stream specified by theWSGI server in environ['wsgi.errors'] (which is usuallysys.stderr). Outside a request, it will log to sys.stderr.

Removing the Default Handler

If you configured logging after accessingapp.logger, and need to remove the defaulthandler, you can import and remove it:

  1. from flask.logging import default_handler
  2.  
  3. app.logger.removeHandler(default_handler)

Email Errors to Admins

When running the application on a remote server for production, you probablywon’t be looking at the log messages very often. The WSGI server will probablysend log messages to a file, and you’ll only check that file if a user tellsyou something went wrong.

To be proactive about discovering and fixing bugs, you can configure alogging.handlers.SMTPHandler to send an email when errors and higherare logged.

  1. import logging
  2. from logging.handlers import SMTPHandler
  3.  
  4. mail_handler = SMTPHandler(
  5. mailhost='127.0.0.1',
  6. fromaddr='[email protected]',
  7. toaddrs=['[email protected]'],
  8. subject='Application Error'
  9. )
  10. mail_handler.setLevel(logging.ERROR)
  11. mail_handler.setFormatter(logging.Formatter(
  12. '[%(asctime)s] %(levelname)s in %(module)s: %(message)s'
  13. ))
  14.  
  15. if not app.debug:
  16. app.logger.addHandler(mail_handler)

This requires that you have an SMTP server set up on the same server. See thePython docs for more information about configuring the handler.

Injecting Request Information

Seeing more information about the request, such as the IP address, may helpdebugging some errors. You can subclass logging.Formatter to injectyour own fields that can be used in messages. You can change the formatter forFlask’s default handler, the mail handler defined above, or any otherhandler.

  1. from flask import has_request_context, request
  2. from flask.logging import default_handler
  3.  
  4. class RequestFormatter(logging.Formatter):
  5. def format(self, record):
  6. if has_request_context():
  7. record.url = request.url
  8. record.remote_addr = request.remote_addr
  9. else:
  10. record.url = None
  11. record.remote_addr = None
  12.  
  13. return super().format(record)
  14.  
  15. formatter = RequestFormatter(
  16. '[%(asctime)s] %(remote_addr)s requested %(url)s\n'
  17. '%(levelname)s in %(module)s: %(message)s'
  18. )
  19. default_handler.setFormatter(formatter)
  20. mail_handler.setFormatter(formatter)

Other Libraries

Other libraries may use logging extensively, and you want to see relevantmessages from those logs too. The simplest way to do this is to add handlersto the root logger instead of only the app logger.

  1. from flask.logging import default_handler
  2.  
  3. root = logging.getLogger()
  4. root.addHandler(default_handler)
  5. root.addHandler(mail_handler)

Depending on your project, it may be more useful to configure each logger youcare about separately, instead of configuring only the root logger.

  1. for logger in (
  2. app.logger,
  3. logging.getLogger('sqlalchemy'),
  4. logging.getLogger('other_package'),
  5. ):
  6. logger.addHandler(default_handler)
  7. logger.addHandler(mail_handler)

Werkzeug

Werkzeug logs basic request/response information to the 'werkzeug' logger.If the root logger has no handlers configured, Werkzeug adds aStreamHandler to its logger.

Flask Extensions

Depending on the situation, an extension may choose to log toapp.logger or its own named logger. Consult eachextension’s documentation for details.