Modifying logging message format based on message logging level in Python3
Question: I asked this question for python 2
[here](http://stackoverflow.com/questions/1343227/can-pythons-logging-format-
be-modified-depending-on-the-message-log-level), but bumped into the issue
again when the the answer no longer worked for Python 3.2.3.

Here's code that works on Python 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")
    

A run 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 requires only a slight mod to
CustomConsoleFormatter.**init**():

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

On 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 being thwarted.

I've tried digging around in Python3 source and it looks like the PercentStyle
instantiation is clobbering self._fmt after I, well, clobber it myself.

My logging chops stop just short of being able to work around this wrinkle.

Can anyone recommend another way or perhaps point out what I'm overlooking?


Answer: With a bit of digging, I was able to modify the Python 2 solution to work with
Python 3. In Python2, it was necessary to temporarily overwrite
`Formatter._fmt`. In Python3, support for multiple format string types
requires us to temporarily overwrite `Formatter._style._fmt` instead.

    
    
    # 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 Halloleo's example of how to use the above in your script (from
the [Python2 version of this
question](http://stackoverflow.com/questions/1343227/can-pythons-logging-
format-be-modified-depending-on-the-message-log-level)):

    
    
    fmt = MyFormatter()
    hdlr = logging.StreamHandler(sys.stdout)
    
    hdlr.setFormatter(fmt)
    logging.root.addHandler(hdlr)
    logging.root.setLevel(DEBUG)
    

