Configuration et utilisation de la journalisation¶
Django contient une configuration de journalisation par défaut fonctionnelle qui peut facilement être étendue.
Appel de journalisation basique¶
Pour envoyer un message de journalisation à partir de votre code, écrivez un appel de journalisation.
Ne soyez pas tenté-e-s d’utiliser des appels de journalisation dans settings.py
.
La façon dont la journalisation de Django est configuré dans le cadre de la fonction setup()
signifie que les appels de journalisation placés dans settings.py
peuvent ne pas fonctionner comme prévu, car la journalisation n’est pas encore configurée à ce stade. Pour explorer la journalisation, utilisez une fonction de vue comme suggéré dans l’exemple ci-dessous.
Tout d’abord, importez la bibliothèque Python logging
et obtenez une instance de journalisation avec logging.getLogger()
. Passez à la méthode getLogger()
un nom pour l’identifier et pour les lignes qu’il produira. Une bonne option est d’utiliser __name__
(voir Utilisation de l’espace de noms des journaliseurs ci-dessous pour en savoir plus), ce qui donnera le nom du module Python actuel sous forme de chemin pointé
import logging
logger = logging.getLogger(__name__)
Par convention, il est bon d’effectuer cette déclaration au niveau du module.
Puis dans une fonction, par exemple dans une vue, envoyez un enregistrement au journaliseur
def some_view(request):
...
if some_risky_state:
logger.warning('Platform is running at risk')
Lorsque ce code est exécuté, un objet LogRecord
contenant ce message sera envoyé au journaliseur. SI vous utilisez la configuration de journalisation de Django par défaut, le message apparaîtra dans la console.
Le niveau WARNING
utilisé dans l’exemple ci-dessus est l’un des quelques niveaux de sévérité de journalisation: DEBUG`, INFO
, WARNING
, ERROR
, CRITICAL
. Un autre exemple pourrait être
logger.critical('Payment system is not responding')
Important
Les enregistrements ayant un niveau plus faible que WARNING
n’apparaîtront pas dans la console par défaut. La modification de ce comportement nécessite une configuration supplémentaire.
Personnalisation de la configuration de journalisation¶
Même si la configuration de journalisation de Django fonctionne telle quelle, vous pouvez contrôler exactement la manière dont vos journaux sont envoyés à diverses destinations, vers des fichiers journaux, des services externes, par courriel, etc. en ajoutant un peu de configuration supplémentaire.
Vous pouvez configurer :
- les correspondances des journaliseurs (logger) pour déterminer quels enregistrements sont envoyés à quels gestionnaires
- les gestionnaires (handler) pour déterminer ce qu’ils font des enregistrements qu’ils reçoivent
- les filtres, pour ajouter du contrôle supplémentaire sur le transfert des enregistrements, et même les modifier sur place
- les formateurs, pour convertir les objets
LogRecord
en une chaîne ou toute autre forme qui soit lisible par les humains ou un autre système
Il existe plusieurs manières de configurer la journalisation. Dans Django, le réglage LOGGING
est le plus couramment utilisé. Ce réglage utilise le format dictConfig, et étend la configuration de journalisation par défaut.
Consultez Configuration de la journalisation pour une explication sur la manière dont vos réglages personnalisés sont fusionnés avec ceux de Django.
Consultez la documentation de journalisation de Python
pour plus de détails sur les autres manières de configurer la journalisation. Par simplification, cette documentation ne va considérer que la configuration au travers du réglage LOGGING
.
Configuration de journalisation basique¶
Lors de la configuration de la journalisation, il est raisonnable de
Créer un dictionnaire LOGGING
¶
Dans votre fichier settings.py
:
LOGGING = {
'version': 1, # the dictConfig format version
'disable_existing_loggers': False, # retain the default loggers
}
Il est presque toujours recommandé de conserver et étendre la configuration de journalisation par défaut en définissant disable_existing_loggers
à False
.
Configurer un gestionnaire¶
Cet exemple configure un seul gestionnaire (handler) nommé file
, qui utilise la classe FileHandler
de Python pour enregistrer les journaux de niveau DEBUG
et plus élevé dans le fichier general.log
(à la racine du projet) :
LOGGING = {
[...]
'handlers': {
'file': {
'class': 'logging.FileHandler',
'filename': 'general.log',
},
},
}
Différentes classes de gestionnaire acceptent différentes options de configuration. Pour plus d’informations sur les classes de gestionnaire disponibles, consultez AdminEmailHandler
fournie par Django et les diverses classes de gestionnaire
fournies par Python.
Les niveaux de journalisation peuvent aussi être définis sur les gestionnaires (par défaut, elles acceptent des messages de tous les niveaux). En utilisant l’exemple ci-dessus, l’ajout de :
{
'class': 'logging.FileHandler',
'filename': 'general.log',
'level': 'DEBUG',
}
définirait une configuration de gestionnaire n’acceptant que des enregistrements de niveau DEBUG
ou supérieur.
Configuration d’une correspondance de journaliseur¶
Pour envoyer des enregistrements à ce gestionnaire, configurez une correspondance pour l’utiliser, par exemple :
LOGGING = {
[...]
'loggers': {
'': {
'level': 'DEBUG',
'handlers': ['file'],
},
},
}
Le nom de correspondance détermine quels sont les enregistrements de journaux qu’il va traiter. Cette configuration (''
) is anonyme. Cela signifie qu’elle traitera les enregistrements de tous les journaliseurs (voir Utilisation de l’espace de noms des journaliseurs ci-dessous sur la manière d’utiliser les noms de correspondance pour déterminer les journaliseurs concernés par le traitement de ses enregistrements).
Ceci va transmettre les messages de niveau DEBUG
et supérieur au gestionnaire nommé file
.
Notez qu’un journaliseur peut transmettre des messages à plusieurs gestionnaires, il existe donc une relation de type plusieurs-à-plusieurs entre les journaliseurs et les gestionnaires.
Si vous exécutez
logger.debug('Attempting to connect to API')
dans vote code, vous trouverez ce message dans le fichier general.log` à la racine de votre projet.
Configuration d’un formateur¶
Par défaut, le résultat final de journalisation contient la partie message de chaque enregistrement de journal
. Utilisez un formateur si vous souhaitez inclure des données supplémentaires. Commencez par nommer et définir vos formateurs. Cet exemple définit des formateurs nommés verbose
et simple
:
LOGGING = {
[...]
'formatters': {
'verbose': {
'format': '{name} {levelname} {asctime} {module} {process:d} {thread:d} {message}',
'style': '{',
},
'simple': {
'format': '{levelname} {message}',
'style': '{',
},
},
}
Le mot-clé style
permet d’indiquer {
pour la mise en forme str.format()
ou $
pour string.Template
; la valeur par défaut est $
.
Voir LogRecord attributes au sujet des attributs de LogRecord
qu’il est possible d’inclure.
Pour appliquer un formateur à un gestionnaire, ajoutez une entrée formatter
au dictionnaire du gestionnaire en vous référant au formateur par son nom, par exemple :
'handlers': {
'file': {
'class': 'logging.FileHandler',
'filename': 'general.log',
'formatter': 'verbose',
},
},
Utilisation de l’espace de noms des journaliseurs¶
La configuration de journalisation anonyme ''
capture les journaux de n’importe quelle application Python. Une configuration de journalisation nommée ne capturera que les journaux de journaliseurs dont le nom correspond.
L’espace de noms d’une instance de journaliseur est défini en utilisant getLogger()
. Par exemple, dans views.py
de my_app
:
logger = logging.getLogger(__name__)
va créer un journaliseur dans l’espace de noms my_app.views
. __name__
permet d’organiser automatiquement les messages de journalisation en fonction de leur provenance dans les applications de votre projet. Cela garantit par la même occasion que les collisions de noms seront évitées.
Une correspondance de journaliseur nommée my_app.views
va capturer les enregistrements de ce journaliseur :
LOGGING = {
[...]
'loggers': {
'my_app.views': {
...
},
},
}
Une correspondance de journaliseur nommée my_app
sera plus permissive, capturant les enregistrements de journaliseurs partout dans l’espace de noms my_app
(y compris my_app.views`, my_app.utils
et ainsi de suite) :
LOGGING = {
[...]
'loggers': {
'my_app': {
...
},
},
}
Il est aussi possible de définir les espaces de noms des journaliseurs de manière explicite
logger = logging.getLogger('project.payment')
et de définir ensuite en fonction les correspondances de journaliseurs.
Utilisation des hiérarchies et de la propagation des journaliseurs¶
La nomenclature des journaliseurs est hiérarchique. my_app
est le parent de my_app.views
, qui est le parent de my_app.views.private
. Sans autre indication, les correspondances de journaliseurs vont propager les enregistrements qu’elles traitent à leurs parents ; un enregistrement d’un journaliseur dans l’espace de noms my_app.views.private
sera traité à la fois par les correspondances de my_app
et de my_app.views
.
Pour contrôler ce comportement, donnez une valeur à la clé de propagation sur les correspondances que vous définissez
LOGGING = {
[...]
'loggers': {
'my_app': {
[...]
},
'my_app.views': {
[...]
},
'my_app.views.private': {
[...]
'propagate': False,
},
},
}
propagate
vaut True
par défaut. Dans cet exemple, les journaux de my_app.views.private
ne seront pas traités par les parents, mais les journaux de my_app.views
le seront.
Configuration de journalisation réactive¶
La journalisation est d’autant plus utile qu’elle contient des informations riches, mais sans information inutile, et cette pesée d’intérêts dépend de ce que vous faites. Lorsque vous êtes en mode débogage, le niveau d’informations souhaité dépasse largement ce qui sera nécessaire lorsque vous passerez votre projet en production.
Vous pouvez configurer la journalisation pour qu’elle vous offre le niveau de détail nécessaire au moment où vous en avez besoin. Au lieu de modifier manuellement la configuration pour cet objectif, une meilleure façon est d’appliquer une configuration automatiquement en fonction de l’environnement.
Par exemple, vous pouvez définir une variable d’environnement DJANGO_LOG_LEVEL
appropriée dans vos environnements de développement et de pré-production, et en faire usage dans une configuration de journaliseur de cette façon
'level': os.getenv('DJANGO_LOG_LEVEL', 'WARNING')
de cette manière, tant que l’environnement n’indique par un niveau de journalisation plus bas, cette configuration ne propagera que les enregistrements de sévérité WARNING
et supérieure à son gestionnaire.
D’autres options de la configuration (comme les options level
ou formatter
des gestionnaires) peuvent également être ajustées de cette façon.