Changing log message format based on message logging level in Python3

I asked this question for python 2 here , but again ran into a problem when the answer no longer worked on Python 3.2.3.

Here is the code that runs on Python 2.7.3:

import logging # Attempt to set up a Python3 logger than will print custom messages # based on each message 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") 

Running using 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 


As far as I can tell, conversion to Python3 only requires a small mod for CustomConsoleFormatter. init ():

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

In 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 


As you can see, my desire to replace β€œ10” with β€œDEBUG” is in the way.

I tried digging into the Python3 source, and it looks like the PercentStyle instance is clobbering self._fmt after I, well, clog it myself.

My chops logs stop, you can hardly get around this wrinkle.

Can someone recommend another way or maybe indicate what I'm missing?

+6
logging
Feb 13 '13 at 1:25
source share
3 answers

With a little digging, I was able to modify the Python 2 solution to work with Python 3. In Python2, it was necessary to temporarily rewrite Formatter._fmt . In Python3, support for multiple types of format strings requires us to temporarily overwrite Formatter._style._fmt .

 # 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 

And here is an example of Halloleo, how to use the above in a script (from the Python2 version of this question ):

 fmt = MyFormatter() hdlr = logging.StreamHandler(sys.stdout) hdlr.setFormatter(fmt) logging.root.addHandler(hdlr) logging.root.setLevel(DEBUG) 
+7
Feb 13 '13 at 17:37
source share
β€” -

Cross-post another answer . This does not work due to the new (3.2+, 3.4 at present) implementation of logging.Formatter , which now uses formatting styles. It depends on the style of the style '{' , but it can be adapted. It can be refined to be more general and allow the choice of formatting style and custom messages as arguments for __init__ too.

 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) 
+2
May 21 '13 at 20:20
source share

I was calmly late for this question, but here is my solution. This follows the original python 2 syntax style. In general, there are three new classes that you should use due to the addition of style support. These are: PercentStyle, StrFormatStyle and 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 
+1
Apr 14 '16 at 15:53
source share



All Articles