129 votes

Comment ajouter un champ personnalisé à la chaîne de format du journal Python ?

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 suis pas sûr de savoir comment faire passer ça. app_name à l'enregistreur pour l'interpoler dans la chaîne de format. Je peux évidemment faire en sorte qu'elle apparaisse dans le message du journal en la passant à chaque fois, mais c'est un peu compliqué.

J'ai essayé :

logging.info('Log message', app_name='myapp')
logging.info('Log message', {'app_name', 'myapp'})
logging.info('Log message', 'myapp')

mais aucune ne fonctionne.

2voto

PriyaGp Points 21

La réponse acceptée ne consignait pas le format dans le fichier journal, alors que le format était reflété dans la sortie sys. Alternativement, j'ai utilisé une approche plus simple et travaillé comme ;

logging.basicConfig(filename="mylogfile.test",
                    filemode="w+",
                    format='%(asctime)s: ' +app_name+': %(message)s ',
                    level=logging.DEBUG)

1voto

Drakes Points 17066

Si vous avez besoin d'une valeur par défaut extra cartographie, et si vous souhaitez le personnaliser pour des messages de journal ad hoc, cela fonctionne dans Python 2.7+ en créant un fichier LoggerAdapter qui fusionne une extra avec n'importe quel extra d'un message donné.

import logging
import os
import sys

logging.basicConfig(
    level=logging.DEBUG,
    format='%(asctime)s %(levelname)-8s Py%(python)-4s pid:%(pid)-5s %(message)s',
)
_logger = logging.getLogger("my-logger")
_logger.setLevel(logging.DEBUG)

class DefaultExtrasAdapter(logging.LoggerAdapter):
    def __init__(self, logger, extra):
        super(DefaultExtrasAdapter, self).__init__(logger, extra)

    def process(self, msg, kwargs):
        # Speed gain if no extras are present
        if "extra" in kwargs:
            copy = dict(self.extra).copy()
            copy.update(kwargs["extra"])
            kwargs["extra"] = copy
        else:
            kwargs["extra"] = self.extra
        return msg, kwargs

LOG = DefaultExtrasAdapter(_logger, {"python": sys.version_info[0], "pid": os.getpid()})

if __name__ == "__main__":
    LOG.info("<-- With defaults")
    LOG.info("<-- With my version", extra={"python": 3.10})
    LOG.info("<-- With my pid", extra={"pid": 0})
    LOG.info("<-- With both", extra={"python": 2.7, "pid": -1})

Résultats :

2021-08-05 18:58:27,308 INFO     Py2    pid:8435  <-- With defaults
2021-08-05 18:58:27,309 INFO     Py3.1  pid:8435  <-- With my version
2021-08-05 18:58:27,309 INFO     Py2    pid:0     <-- With my pid
2021-08-05 18:58:27,309 INFO     Py2.7  pid:-1    <-- With both

0voto

Yaniv K. Points 150

En utilisant la réponse de mr2ert, j'ai trouvé cette solution confortable (bien que je suppose que ce n'est pas recommandé) - Remplacer les méthodes de journalisation intégrées pour accepter l'argument personnalisé et créer le fichier extra dans les 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

Il s'agit de 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)

0voto

user3672617 Points 9

Importation de l'enregistrement ;

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') ;

classe Logger :

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)

classe Test : logger = Logger.getLogger('Test')

if __name__=='__main__':
    logger.logMessage('ERROR','123','This is an error')

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X