mirror of https://github.com/mitsuhiko/flask.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
175 lines
5.5 KiB
175 lines
5.5 KiB
.. _logging: |
|
|
|
Logging |
|
======= |
|
|
|
Flask uses standard Python :mod:`logging`. All Flask-related messages are |
|
logged under the ``'flask'`` logger namespace. |
|
:meth:`Flask.logger <flask.Flask.logger>` returns the logger named |
|
``'flask.app'``, and can be used to log messages for your application. :: |
|
|
|
@app.route('/login', methods=['POST']) |
|
def login(): |
|
user = get_user(request.form['username']) |
|
|
|
if user.check_password(request.form['password']): |
|
login_user(user) |
|
app.logger.info('%s logged in successfully', user.username) |
|
return redirect(url_for('index')) |
|
else: |
|
app.logger.info('%s failed to log in', user.username) |
|
abort(401) |
|
|
|
|
|
Basic Configuration |
|
------------------- |
|
|
|
When you want to configure logging for your project, you should do it as soon |
|
as possible when the program starts. If :meth:`app.logger <flask.Flask.logger>` |
|
is accessed before logging is configured, it will add a default handler. If |
|
possible, configure logging before creating the application object. |
|
|
|
This example uses :func:`~logging.config.dictConfig` to create a logging |
|
configuration similar to Flask's default, except for all logs:: |
|
|
|
from logging.config import dictConfig |
|
|
|
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__) |
|
|
|
|
|
Default Configuration |
|
````````````````````` |
|
|
|
If you do not configure logging yourself, Flask will add a |
|
:class:`~logging.StreamHandler` to :meth:`app.logger <flask.Flask.logger>` |
|
automatically. During requests, it will write to the stream specified by the |
|
WSGI server in ``environ['wsgi.errors']`` (which is usually |
|
:data:`sys.stderr`). Outside a request, it will log to :data:`sys.stderr`. |
|
|
|
|
|
Removing the Default Handler |
|
```````````````````````````` |
|
|
|
If you configured logging after accessing |
|
:meth:`app.logger <flask.Flask.logger>`, and need to remove the default |
|
handler, you can import and remove it:: |
|
|
|
from flask.logging import default_handler |
|
|
|
app.logger.removeHandler(default_handler) |
|
|
|
|
|
Email Errors to Admins |
|
---------------------- |
|
|
|
When running the application on a remote server for production, you probably |
|
won't be looking at the log messages very often. The WSGI server will probably |
|
send log messages to a file, and you'll only check that file if a user tells |
|
you something went wrong. |
|
|
|
To be proactive about discovering and fixing bugs, you can configure a |
|
:class:`logging.handlers.SMTPHandler` to send an email when errors and higher |
|
are logged. :: |
|
|
|
import logging |
|
from logging.handlers import SMTPHandler |
|
|
|
mail_handler = SMTPHandler( |
|
mailhost='127.0.0.1', |
|
fromaddr='server-error@example.com', |
|
toaddrs=['admin@example.com'], |
|
subject='Application Error' |
|
) |
|
mail_handler.setLevel(logging.ERROR) |
|
mail_handler.setFormatter(logging.Formatter( |
|
'[%(asctime)s] %(levelname)s in %(module)s: %(message)s' |
|
)) |
|
|
|
if not app.debug: |
|
app.logger.addHandler(mail_handler) |
|
|
|
This requires that you have an SMTP server set up on the same server. See the |
|
Python docs for more information about configuring the handler. |
|
|
|
|
|
Injecting Request Information |
|
----------------------------- |
|
|
|
Seeing more information about the request, such as the IP address, may help |
|
debugging some errors. You can subclass :class:`logging.Formatter` to inject |
|
your own fields that can be used in messages. You can change the formatter for |
|
Flask's default handler, the mail handler defined above, or any other |
|
handler. :: |
|
|
|
from flask import request |
|
from flask.logging import default_handler |
|
|
|
class RequestFormatter(logging.Formatter): |
|
def format(self, record): |
|
record.url = request.url |
|
record.remote_addr = request.remote_addr |
|
return super().format(record) |
|
|
|
formatter = RequestFormatter( |
|
'[%(asctime)s] %(remote_addr)s requested %(url)s\n' |
|
'%(levelname)s in %(module)s: %(message)s' |
|
)) |
|
default_handler.setFormatter(formatter) |
|
mail_handler.setFormatter(formatter) |
|
|
|
|
|
Other Libraries |
|
--------------- |
|
|
|
Other libraries may use logging extensively, and you want to see relevant |
|
messages from those logs too. The simplest way to do this is to add handlers |
|
to the root logger instead of only the app logger. :: |
|
|
|
from flask.logging import default_handler |
|
|
|
root = logging.getLogger() |
|
root.addHandler(default_handler) |
|
root.addHandler(mail_handler) |
|
|
|
Depending on your project, it may be more useful to configure each logger you |
|
care about separately, instead of configuring only the root logger. :: |
|
|
|
for logger in ( |
|
app.logger, |
|
logging.getLogger('sqlalchemy'), |
|
logging.getLogger('other_package'), |
|
): |
|
logger.addHandler(default_handler) |
|
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 a |
|
:class:`~logging.StreamHandler` to its logger. |
|
|
|
|
|
Flask Extensions |
|
```````````````` |
|
|
|
Depending on the situation, an extension may choose to log to |
|
:meth:`app.logger <flask.Flask.logger>` or its own named logger. Consult each |
|
extension's documentation for details.
|
|
|