simplify logging configuration
single default handler and formatter don't remove handlers configure level once using setLevel document logging reorganize logging tests
This commit is contained in:
parent
85fa8aabf5
commit
66b1b752da
13 changed files with 399 additions and 451 deletions
175
docs/logging.rst
Normal file
175
docs/logging.rst
Normal file
|
|
@ -0,0 +1,175 @@
|
|||
.. _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.
|
||||
Loading…
Add table
Add a link
Reference in a new issue