Journalisation¶
Flask utilise le module Python logging
standard. Les messages de votre application Flask sont transmis via la méthode app.logger
qui utilise le même nom que app.name
. Ce logger peut également être utilisé pour enregistrer vos propres messages.
@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)
Si vous ne configurez pas la journalisation, le niveau de log par défaut de Python est généralement « warning ». Aucun message dont le niveau est situé sous celui configuré ne sera enregistré.
Configuration de base¶
Lorsque vous souhaitez configurer la journalisation de votre projet, vous devez le faire dès que possible lorsque l’application démarre. Si la méthode app.logger
est appelée avant que la journalisation soit configurée, elle utilisera le gestionnaire par défaut. Il est donc recommandé de configurer la journalisation avant même la création de l’objet application.
Cet exemple utilise dictConfig()
afin de créer une configuration similaire à celle par défaut de Flask pour l’ensemble de la journalisation:
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__)
Configuration par défaut¶
Si vous ne configurez pas la journalisation, Flask ajoutera automatiquement un StreamHandler
à la méthode app.logger
. Lors de chaque appel à une requête, il écrira alors dans le flux spécifié par le serveur WSGI via environ['wsgi.errors']
(qui vaut en général sys.stderr
). Hors des appels aux requêtes, il écrira sur sys.stderr
.
Supprimer le gestionnaire par défaut¶
Si vous configurez la journalisation après avoir accédé à la méthode app.logger
, et que vous souhaitez retirer le gestionnaire par défaut, vous pouvez l’importez pour le supprimer:
from flask.logging import default_handler
app.logger.removeHandler(default_handler)
Envoyer les erreurs par mail aux admins¶
Lorsque l’application est exécutée sur un serveur de production, il est sans doute peu vraisemblable que vous regarderez les messages de logs régulièrement. Le serveur WSGI enverra probablement les messages dans un fichier qui ne sera alors exploité que lorsqu’un utilisateur signalera qu’un problème est survenu.
Afin d’être proactif sur les problèmes, vous pouvez configurer un gestionnaire SMTP logging.handlers.SMTPHandler
afin de transmettre les messages de niveau « erreur » et plus par mail.
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)
Cela nécessite un serveur SMTP configuré sur le même serveur. Voir la documentation Python pour plus d’informations sur la configuration de ce gestionnaire.
Ajouter des informations de la Requête¶
Avoir plus d’information à propos de la requête traitée, comme une adresse IP, peut vous aider à résoudre vos problèmes. Vous pouvez créer une sous-classe de logging.Formatter
afin d’injecter vos propres données dans les messages. Vous pouvez adapter le formatage du gestionnaire par défaut de Flask, le gestionnaire par mail défini ci-dessus, ou n’importe quel autre.
from flask import has_request_context, request
from flask.logging import default_handler
class RequestFormatter(logging.Formatter):
def format(self, record):
if has_request_context():
record.url = request.url
record.remote_addr = request.remote_addr
else:
record.url = None
record.remote_addr = None
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)
Autres librairies¶
D’autres librairies peuvent utiliser la journalisation et il est alors nécessaire de récupérer leurs messages. La manière la plus simple est d’ajouter des gestionnaires au logger racine en plus de celui de l’application.
from flask.logging import default_handler
root = logging.getLogger()
root.addHandler(default_handler)
root.addHandler(mail_handler)
Cependant, et suivant votre projet, il peut être plus intéressant de configurer chaque logger séparément au lieu d’utiliser seulement le logger racine.
for logger in (
app.logger,
logging.getLogger('sqlalchemy'),
logging.getLogger('other_package'),
):
logger.addHandler(default_handler)
logger.addHandler(mail_handler)
Werkzeug¶
Werkzeug utilise son propre logger 'werkzeug'
pour écrire les informations basiques des requêtes et des réponses. Si le logger racine n’a pas de gestionnaire configuré, Werkzeug ajoute une classe StreamHandler
à son logger.
Les extensions Flask¶
Certaines extensions peuvent choisir d’utiliser la méthode app.logger
ou bien leur propre logger pour leur journalisation. Il est nécessaire de vérifier la documentation de chaque extension pour les détails à ce sujet.