Ma chaîne de format actuelle est:
formatter = logging.Formatter('%(asctime)s : %(message)s')
et je veux ajouter un nouveau champ appelé app_name et qui aura une valeur différente dans chaque script qui contient ce formateur.
import logging
formatter = logging.Formatter('%(asctime)s %(app_name)s : %(message)s')
syslog.setFormatter(formatter)
logger.addHandler(syslog)
Mais je ne sais pas comment passer ça app_name
valeur à l'enregistreur à interpoler dans la chaîne de format. Je peux évidemment le faire apparaître dans le message de journal mais en le passant à chaque fois mais c'est désordonné.
J'ai essayé:
logging.info('Log message', app_name='myapp')
logging.info('Log message', {'app_name', 'myapp'})
logging.info('Log message', 'myapp')
mais aucun ne fonctionne.
Vous pouvez utiliser un LoggerAdapter pour ne pas avoir à transmettre les informations supplémentaires à chaque appel de journalisation:
import logging
extra = {'app_name':'Super App'}
logger = logging.getLogger(__name__)
syslog = logging.StreamHandler()
formatter = logging.Formatter('%(asctime)s %(app_name)s : %(message)s')
syslog.setFormatter(formatter)
logger.setLevel(logging.INFO)
logger.addHandler(syslog)
logger = logging.LoggerAdapter(logger, extra)
logger.info('The sky is so blue')
journaux (quelque chose comme)
2013-07-09 17:39:33,596 Super App : The sky is so blue
Filtres peut également être utilisé pour ajouter des informations contextuelles.
import logging
class AppFilter(logging.Filter):
def filter(self, record):
record.app_name = 'Super App'
return True
logger = logging.getLogger(__name__)
logger.addFilter(AppFilter())
syslog = logging.StreamHandler()
formatter = logging.Formatter('%(asctime)s %(app_name)s : %(message)s')
syslog.setFormatter(formatter)
logger.setLevel(logging.INFO)
logger.addHandler(syslog)
logger.info('The sky is so blue')
produit un enregistrement de journal similaire.
Vous devez passer le dict comme paramètre à extra pour le faire de cette façon.
logging.info('Log message', extra={'app_name': 'myapp'})
Preuve:
>>> import logging
>>> logging.basicConfig(format="%(foo)s - %(message)s")
>>> logging.warning('test', extra={'foo': 'bar'})
bar - test
De plus, si vous essayez d'enregistrer un message sans passer le dict, il échouera.
>>> logging.warning('test')
Traceback (most recent call last):
File "/usr/lib/python2.7/logging/__init__.py", line 846, in emit
msg = self.format(record)
File "/usr/lib/python2.7/logging/__init__.py", line 723, in format
return fmt.format(record)
File "/usr/lib/python2.7/logging/__init__.py", line 467, in format
s = self._fmt % record.__dict__
KeyError: 'foo'
Logged from file <stdin>, line 1
Une autre façon consiste à créer un LoggerAdapter personnalisé. Ceci est particulièrement utile lorsque vous ne pouvez pas changer le format OR si votre format est partagé avec du code qui n'envoie pas la clé unique (dans votre cas nom_app):
class LoggerAdapter(logging.LoggerAdapter):
def __init__(self, logger, prefix):
super(LoggerAdapter, self).__init__(logger, {})
self.prefix = prefix
def process(self, msg, kwargs):
return '[%s] %s' % (self.prefix, msg), kwargs
Et dans votre code, vous devez créer et initialiser votre enregistreur comme d'habitude:
logger = logging.getLogger(__name__)
# Add any custom handlers, formatters for this logger
myHandler = logging.StreamHandler()
myFormatter = logging.Formatter('%(asctime)s %(message)s')
myHandler.setFormatter(myFormatter)
logger.addHandler(myHandler)
logger.setLevel(logging.INFO)
Enfin, vous devez créer l'adaptateur wrapper pour ajouter un préfixe selon les besoins:
logger = LoggerAdapter(logger, 'myapp')
logger.info('The world bores you when you are cool.')
La sortie ressemblera à ceci:
2013-07-09 17:39:33,596 [myapp] The world bores you when you are cool.
En utilisant la réponse de mr2ert, j'ai trouvé cette solution confortable (bien que je suppose que ce n'est pas recommandé) - Remplacez les méthodes de journalisation intégrées pour accepter l'argument personnalisé et créer le dictionnaire extra
à l'intérieur des méthodes:
import logging
class CustomLogger(logging.Logger):
def debug(self, msg, foo, *args, **kwargs):
extra = {'foo': foo}
if self.isEnabledFor(logging.DEBUG):
self._log(logging.DEBUG, msg, args, extra=extra, **kwargs)
*repeat for info, warning, etc*
logger = CustomLogger('CustomLogger', logging.DEBUG)
formatter = logging.Formatter('%(asctime)s [%(foo)s] %(message)s')
handler = logging.StreamHandler()
handler.setFormatter(formatter)
logger.addHandler(handler)
logger.debug('test', 'bar')
Sortie:
2019-03-02 20:06:51,998 [bar] test
Ceci est la fonction intégrée pour référence:
def debug(self, msg, *args, **kwargs):
"""
Log 'msg % args' with severity 'DEBUG'.
To pass exception information, use the keyword argument exc_info with
a true value, e.g.
logger.debug("Houston, we have a %s", "thorny problem", exc_info=1)
"""
if self.isEnabledFor(DEBUG):
self._log(DEBUG, msg, args, **kwargs)