2013-02-13 5 views
6

Ich stellte diese Frage für Python 2 here, stieß aber erneut auf das Problem, wenn die Antwort für Python 3.2.3 nicht mehr funktionierte.Ändern von Protokollierungsnachrichtenformat basierend auf Nachrichtenprotokollierungsgrad in Python3

Hier ist Code, der auf Python arbeitet 2.7.3:

import logging 

# Attempt to set up a Python3 logger than will print custom messages 
# based on each message's logging level. 
# The technique recommended for Python2 does not appear to work for 
# Python3 

class CustomConsoleFormatter(logging.Formatter): 
    """ 
    Modify the way DEBUG messages are displayed. 

    """ 
    def __init__(self, fmt="%(levelno)d: %(msg)s"): 
     logging.Formatter.__init__(self, fmt=fmt) 

    def format(self, record): 

     # Remember the original format 
     format_orig = self._fmt 

     if record.levelno == logging.DEBUG: 
      self._fmt = "DEBUG: %(msg)s" 

     # Call the original formatter to do the grunt work 
     result = logging.Formatter.format(self, record) 

     # Restore the original format 
     self._fmt = format_orig 

     return result 


# Set up a logger 
my_logger = logging.getLogger("my_custom_logger") 
my_logger.setLevel(logging.DEBUG) 

my_formatter = CustomConsoleFormatter() 

console_handler = logging.StreamHandler() 
console_handler.setFormatter(my_formatter) 

my_logger.addHandler(console_handler) 

my_logger.debug("This is a DEBUG-level message") 
my_logger.info("This is an INFO-level message") 

Ein Lauf mit Python 2.7.3:

tcsh-16: python demo_python_2.7.3.py 
DEBUG: This is a DEBUG-level message 
20: This is an INFO-level message 


Soweit ich das beurteilen kann, Umstellung auf Python3 benötigt nur einen kleinen Mod zu CustomConsoleFormatter. init():

def __init__(self): 
    super().__init__(fmt="%(levelno)d: %(msg)s", datefmt=None, style='%') 

auf Python 3.2.3:

tcsh-26: python3 demo_python_3.2.3.py 
10: This is a DEBUG-level message 
20: This is an INFO-level message 


Wie Sie sehen können, mein Wunsch zu ersetzen '10' mit 'DEBUG' vereitelt wird.

Ich habe versucht, in Python3 Quelle herum zu graben und es sieht aus wie die PercentStyle Instanziierung ist Clobbering self._fmt nach mir, na ja, es selbst Clobber.

Meine Logging Chops stoppen nur kurz in der Lage, um diese Falte zu arbeiten.

Kann jemand einen anderen Weg empfehlen oder vielleicht darauf hinweisen, was ich übersehe?

Antwort

7

Mit ein wenig Graben konnte ich die Python 2-Lösung ändern, um mit Python 3 zu arbeiten. In Python2 war es notwendig, Formatter._fmt vorübergehend zu überschreiben. In Python3 erfordert die Unterstützung für mehrere Formatzeichentypen, dass wir stattdessen Formatter._style._fmt temporär überschreiben.

# Custom formatter 
class MyFormatter(logging.Formatter): 

    err_fmt = "ERROR: %(msg)s" 
    dbg_fmt = "DBG: %(module)s: %(lineno)d: %(msg)s" 
    info_fmt = "%(msg)s" 

    def __init__(self): 
     super().__init__(fmt="%(levelno)d: %(msg)s", datefmt=None, style='%') 

    def format(self, record): 

     # Save the original format configured by the user 
     # when the logger formatter was instantiated 
     format_orig = self._style._fmt 

     # Replace the original format with one customized by logging level 
     if record.levelno == logging.DEBUG: 
      self._style._fmt = MyFormatter.dbg_fmt 

     elif record.levelno == logging.INFO: 
      self._style._fmt = MyFormatter.info_fmt 

     elif record.levelno == logging.ERROR: 
      self._style._fmt = MyFormatter.err_fmt 

     # Call the original formatter class to do the grunt work 
     result = logging.Formatter.format(self, record) 

     # Restore the original format configured by the user 
     self._style._fmt = format_orig 

     return result 

Und hier ist Halloleo das Beispiel dafür, wie die oben in Ihrem Skript zu verwenden (vom Python2 version of this question):

fmt = MyFormatter() 
hdlr = logging.StreamHandler(sys.stdout) 

hdlr.setFormatter(fmt) 
logging.root.addHandler(hdlr) 
logging.root.setLevel(DEBUG) 
2

Cross-Posting von another answer. Es funktioniert nicht wegen der neuen (3.2+, 3.4 ab sofort) Implementierung von logging.Formatter, die jetzt auf Formatierungsstile angewiesen ist. Dies beruht auf dem Format '{', aber es kann angepasst werden. Kann verfeinert werden, um allgemeiner zu sein und erlaubt die Auswahl von Formatierungsstil und benutzerdefinierten Nachrichten als Argumente zu __init__ auch.

class SpecialFormatter(logging.Formatter): 
    FORMATS = {logging.DEBUG : logging._STYLES['{']("{module} DEBUG: {lineno}: {message}"), 
      logging.ERROR : logging._STYLES['{']("{module} ERROR: {message}"), 
      logging.INFO : logging._STYLES['{']("{module}: {message}"), 
      'DEFAULT' : logging._STYLES['{']("{module}: {message}")} 

    def format(self, record): 
     # Ugly. Should be better 
     self._style = self.FORMATS.get(record.levelno, self.FORMATS['DEFAULT']) 
     return logging.Formatter.format(self, record) 

hdlr = logging.StreamHandler(sys.stderr) 
hdlr.setFormatter(SpecialFormatter()) 
logging.root.addHandler(hdlr) 
logging.root.setLevel(logging.INFO) 
1

Ich bin ruhig spät für diese Frage, aber hier ist meine Lösung. Es folgt dem ursprünglichen Python 2-Syntax-Stil. Im Allgemeinen gibt es drei neue Klassen, die Sie wegen der Unterstützung von Stilen verwenden sollten. Dies sind: PercentStyle, StrFormatStyle und StringTemplateStyle.

from logging import Formatter, PercentStyle, ERROR, WARNING, INFO, DEBUG 
class SrvLogFormat(Formatter): 
    def __init__(self): 
     super().__init__(fmt=env.fmt_log, datefmt=env.fmt_log_date) 

    def format(self, record): 
     original_style = self._style 

     if record.levelno == DEBUG: 
      self._style = PercentStyle(env.fmt_dflt) 
     if record.levelno == INFO: 
      self._style = PercentStyle(env.fmt_dflt) 
     if record.levelno == WARNING: 
      self._style = PercentStyle(env.fmt_dflt) 
     if record.levelno == ERROR: 
      self._style = PercentStyle(env.fmt_err) 

     result = Formatter.format(self, record) 
     self._style = original_style 
     return result 
Verwandte Themen