Je n'arrive pas à comprendre comment configurer un enregistreur "par défaut" pour mon installation Django. Je souhaite utiliser le nouveau paramètre LOGGING
de Django 1.3 dans settings.py
.
J'ai consulté l'exemple de Django Logging Doc , mais il me semble qu'ils configurent uniquement des gestionnaires qui effectueront la journalisation pour des enregistreurs particuliers. Dans le cas de leur exemple, ils configurent un gestionnaire pour les enregistreurs nommés "Django", "Django.request" et "myproject.custom".
Tout ce que je veux faire est de configurer un logging.handlers.RotatingFileHandler
par défaut qui gérera tous les enregistreurs par défaut. c’est-à-dire que si je crée un nouveau module quelque part dans mon projet et qu’il est désigné par quelque chose comme: my_app_name.my_new_module
, je devrais pouvoir le faire et avoir tous les enregistrements dans les journaux de rotation des fichiers.
# In file './my_app_name/my_new_module.py'
import logging
logger = logging.getLogger('my_app_name.my_new_module')
logger.debug('Hello logs!') # <-- This should get logged to my RotatingFileHandler that I setup in `settings.py`!
Deviner...
Vous définissez le journal "catch all" en le référençant avec la chaîne vide: ''
.
Par exemple, dans la configuration suivante, tous les événements de journal sont enregistrés dans logs/mylog.log
, à l'exception de Django.request
événements de journal, qui seront enregistrés dans logs/Django_request.log
. Étant donné que 'propagate'
est défini sur False
pour mon enregistreur Django.request
, l'événement de journalisation n'atteindra jamais l'enregistreur 'catch all'.
LOGGING = {
'version': 1,
'disable_existing_loggers': True,
'formatters': {
'standard': {
'format': '%(asctime)s [%(levelname)s] %(name)s: %(message)s'
},
},
'handlers': {
'default': {
'level':'DEBUG',
'class':'logging.handlers.RotatingFileHandler',
'filename': 'logs/mylog.log',
'maxBytes': 1024*1024*5, # 5 MB
'backupCount': 5,
'formatter':'standard',
},
'request_handler': {
'level':'DEBUG',
'class':'logging.handlers.RotatingFileHandler',
'filename': 'logs/Django_request.log',
'maxBytes': 1024*1024*5, # 5 MB
'backupCount': 5,
'formatter':'standard',
},
},
'loggers': {
'': {
'handlers': ['default'],
'level': 'DEBUG',
'propagate': True
},
'Django.request': {
'handlers': ['request_handler'],
'level': 'DEBUG',
'propagate': False
},
}
}
Comme vous l'avez dit dans votre réponse , Chris, une option pour définir un enregistreur par défaut consiste à utiliser la chaîne vide comme clé.
Cependant, je pense que le moyen envisagé est de définir un enregistreur spécial sous la clé root
du dictionnaire de configuration de journalisation. J'ai trouvé ceci dans la documentation Python :
root - ce sera la configuration du logger racine. Le traitement de la configuration sera identique à celui de tout enregistreur, sauf que le paramètre
propagate
ne sera pas applicable.
Voici la configuration de votre réponse modifiée pour utiliser la clé root
:
LOGGING = {
'version': 1,
'disable_existing_loggers': True,
'formatters': {
'standard': {
'format': '%(asctime)s [%(levelname)s] %(name)s: %(message)s'
},
},
'handlers': {
'default': {
'level':'DEBUG',
'class':'logging.handlers.RotatingFileHandler',
'filename': 'logs/mylog.log',
'maxBytes': 1024*1024*5, # 5 MB
'backupCount': 5,
'formatter':'standard',
},
'request_handler': {
'level':'DEBUG',
'class':'logging.handlers.RotatingFileHandler',
'filename': 'logs/Django_request.log',
'maxBytes': 1024*1024*5, # 5 MB
'backupCount': 5,
'formatter':'standard',
},
},
'root': {
'handlers': ['default'],
'level': 'DEBUG'
},
'loggers': {
'Django.request': {
'handlers': ['request_handler'],
'level': 'DEBUG',
'propagate': False
},
}
}
Pour être juste, je ne vois aucune différence de comportement entre les deux configurations. Il semble que définir un enregistreur avec une clé de chaîne vide modifiera l'enregistreur racine, car logging.getLogger('')
renverra l'enregistreur racine.
La seule raison pour laquelle je préfère 'root'
à ''
est qu’il est explicite de modifier le journal racine. Si vous êtes curieux, 'root'
remplace ''
si vous définissez les deux, simplement parce que l'entrée racine est traitée en dernier.
import logging
logger = logging.getLogger(__name__)
après ajouter:
logging.basicConfig(
level = logging.DEBUG,
format = '%(name)s %(levelname)s %(message)s',
)
nous pouvons changer le format en:
format = '"%(levelname)s:%(name)s:%(message)s" ',
ou
format = '%(name)s %(asctime)s %(levelname)s %(message)s',
J'ai fait un exemple rapide pour vérifier quelle configuration est utilisée lorsque la clé root
et le consignateur ''
vides sont référencés dans config dict.
import logging.config
LOGGING = {
'version': 1,
'disable_existing_loggers': False,
'formatters': {
'fmt1': {
'format': '[FMT1] %(asctime)-15s %(message)s',
},
'fmt2': {
'format': '[FMT2] %(asctime)-15s %(message)s',
}
},
'handlers': {
'console1': {
'level': 'INFO',
'class': 'logging.StreamHandler',
'formatter': 'fmt1',
},
'console2': {
'level': 'INFO',
'class': 'logging.StreamHandler',
'formatter': 'fmt2',
},
},
# First config for root logger: console1 -> fmt1
'root': {
'handlers': ['console1'],
'level': 'DEBUG',
'propagate': True,
},
'loggers': {
# Second config for root logger: console2 -> fmt2
'': {
'handlers': ['console2'],
'level': 'DEBUG',
'propagate': True,
},
},
}
logging.config.dictConfig(LOGGING)
l1 = logging.getLogger()
l2 = logging.getLogger('')
root = logging.root
l1.info("l1")
l2.info("l2")
root.info("root logger")
Imprime le résultat suivant:
[FMT1] 2018-12-18 17:24:47,691 l1
[FMT1] 2018-12-18 17:24:47,691 l2
[FMT1] 2018-12-18 17:24:47,691 root logger
indiquant que la configuration sous la clé root
a la priorité la plus élevée. Si le bloc est supprimé, le résultat est le suivant:
[FMT2] 2018-12-18 17:25:43,757 l1
[FMT2] 2018-12-18 17:25:43,757 l2
[FMT2] 2018-12-18 17:25:43,757 root logger
Dans les deux cas, j'ai pu déboguer et déterminer que les trois enregistreurs (l1
, l2
et root
) faisaient référence à la même instance d'enregistreur, l'enregistreur racine.
J'espère que cela aidera d'autres personnes qui, comme moi, ont été déroutées par les deux façons différentes de configurer le consignateur racine.