Ma chaîne de format actuelle est:
formatter = logging.Formatter('%(asctime)s : %(message)s')
et je veux ajouter un nouveau champ appelé app_name
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 transmettre cette app_name
valeur à l'enregistreur pour interpoler dans la chaîne de format. Je peux évidemment le faire apparaître dans le message de journal en le passant à chaque fois, mais c'est compliqué.
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.
log
appel? Si c'est le cas, regardez la documentation où il est dit "Cette fonctionnalité peut être utilisée pour injecter vos propres valeurs dans un LogRecord ..." Mais cela semble être un cas de choix pour l'utiliserlogger = logging.getLogger('myapp')
et le faire cuire dans l'logger.info
appel.logger
objet dans chaque application, vous pouvez faire de chacun un nom différent par instanciation voslogger
s comme ceci:logger = logging.getLogger(myAppName)
. notez qu'il__name__
s'agit du nom du module python, donc si chaque application est son propre module python, cela fonctionnerait également.Réponses:
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
Les filtres peuvent également être utilisés 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.
la source
config.ini
fichier? Je souhaite ajouter le nom d'hôte actuelsocket.gethostname()
.import uuid uniqueId = str(uuid.uuid4()) extra = {"u_id" : uniqueId} RotatingHandler = RotatingFileHandler(LOG_FILENAME,encoding='utf-8',maxBytes=maxSize, backupCount=batchSize) logger.basicConfig(handlers=[RotatingHandler],level=logLevel.upper(),format='%(levelname)s %(u_id)s %(funcName)s %(asctime)s %(message)s ',datefmt='%m/%d/%Y %I:%M:%S %p') logger = logger.LoggerAdapter(logger=logger, extra=extra)
Vous devez passer le dict en tant que 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 de consigner un message sans passer le dict, cela é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
la source
logging.info()
? Cela a échoué la dernière fois que j'ai essayé. : /logging.Formatter
classe: class CustomFormatter (logging.Formatter): def format (self, record): sinon hasattr (record, 'foo'): record.foo = 'default_foo' return super (CustomFormatter, self.format (enregistrement) h = loggin.StreamHandler () h.setFormatter (CustomFormatter ('% (foo) s% (message) s') logger = logging.getLogger ('bar') logger.addHandler ( h) logger.error ('hey!', extra = {'foo': 'FOO'}) logger.error ('hey!')Python3
Depuis Python3.2, vous pouvez désormais utiliser LogRecordFactory
>>> import logging >>> logging.basicConfig(format="%(custom_attribute)s - %(message)s") >>> old_factory = logging.getLogRecordFactory() >>> def record_factory(*args, **kwargs): record = old_factory(*args, **kwargs) record.custom_attribute = "my-attr" return record >>> logging.setLogRecordFactory(record_factory) >>> logging.info("hello") my-attr - hello
Bien sûr, il
record_factory
peut être personnalisé pour être appelable et la valeur decustom_attribute
pourrait être mise à jour si vous conservez une référence à la fabrique appelable.Pourquoi est-ce mieux que d'utiliser des adaptateurs / filtres?
logger = logging.getLogger(..)
) auraient maintenant le même format de journal. (ce n'est pas le cas avec les filtres / adaptateurs où vous devez utiliser le même objet enregistreur)la source
Une autre méthode consiste à créer un LoggerAdapter personnalisé. Ceci est particulièrement utile lorsque vous ne pouvez pas modifier le format OU si votre format est partagé avec du code qui n'envoie pas la clé unique (dans votre cas app_name ):
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 créez et initialisez 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 créerez l'adaptateur wrapper pour ajouter un préfixe si nécessaire:
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.
la source
J'ai trouvé cette question SO après l'avoir mise en œuvre moi-même. J'espère que ça aide quelqu'un. Dans le code ci-dessous, j'induit une clé supplémentaire appelée
claim_id
au format enregistreur. Il enregistrera le claim_id chaque fois qu'uneclaim_id
clé est présente dans l'environnement. Dans mon cas d'utilisation, j'avais besoin de consigner ces informations pour une fonction AWS Lambda.import logging import os LOG_FORMAT = '%(asctime)s %(name)s %(levelname)s %(funcName)s %(lineno)s ClaimID: %(claim_id)s: %(message)s' class AppLogger(logging.Logger): # Override all levels similarly - only info overriden here def info(self, msg, *args, **kwargs): return super(AppLogger, self).info(msg, extra={"claim_id": os.getenv("claim_id", "")}) def get_logger(name): """ This function sets log level and log format and then returns the instance of logger""" logging.setLoggerClass(AppLogger) logging.basicConfig(level=logging.INFO, format=LOG_FORMAT) logger = logging.getLogger(name) logger.setLevel(logging.INFO) return logger LOGGER = get_logger(__name__) LOGGER.info("Hey") os.environ["claim_id"] = "12334" LOGGER.info("Hey")
Gist: https://gist.github.com/ramanujam/306f2e4e1506f302504fb67abef50652
la source
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
extra
dictionnaire à 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')
Production:
2019-03-02 20:06:51,998 [bar] test
Voici 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)
la source
journalisation des importations;
classe LogFilter (logging.Filter):
def __init__(self, code): self.code = code def filter(self, record): record.app_code = self.code return True
logging.basicConfig (format = '[% (asctime) s:% (levelname) s] :: [% (module) s ->% (name) s] - APP_CODE:% (app_code) s - MSG:% (message ) s ');
enregistreur de classe:
def __init__(self, className): self.logger = logging.getLogger(className) self.logger.setLevel(logging.ERROR) @staticmethod def getLogger(className): return Logger(className) def logMessage(self, level, code, msg): self.logger.addFilter(LogFilter(code)) if level == 'WARN': self.logger.warning(msg) elif level == 'ERROR': self.logger.error(msg) else: self.logger.info(msg)
Test de classe: logger = Logger.getLogger ('Test')
if __name__=='__main__': logger.logMessage('ERROR','123','This is an error')
la source