Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Modifying logging message format based on message logging level in Python3

Tags:

I asked this question for python 2 here, 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?

like image 291
JS. Avatar asked Feb 13 '13 01:02

JS.


People also ask

How do I change the logger format in Python?

stderr ) and a default format for the displayed message before delegating to the root logger to do the actual message output. You can change this by passing a format string to basicConfig() with the format keyword argument. For all options regarding how a format string is constructed, see Formatter Objects.

What are the five levels of logging in Python?

In Python, the built-in logging module can be used to log events. Log messages can have 5 levels - DEBUG, INGO, WARNING, ERROR and CRITICAL. They can also include traceback information for exceptions. Logs can be especially useful in case of errors to help identify their cause.

How do I use logging config in Python?

Logging in PythonYou can configure logging using the module and class functions or by creating a config file or a dictionary and loading it using fileConfig() or dictConfig() respectively. These are useful in case you want to change your logging configuration in a running application.

What is level in logging in Python?

Python Logging Levels There are six log levels in Python; each level is associated with an integer that indicates the log severity: NOTSET=0, DEBUG=10, INFO=20, WARN=30, ERROR=40, and CRITICAL=50. All the levels are rather straightforward (DEBUG < INFO < WARN ) except NOTSET, whose particularity will be addressed next.


1 Answers

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):

fmt = MyFormatter() hdlr = logging.StreamHandler(sys.stdout)  hdlr.setFormatter(fmt) logging.root.addHandler(hdlr) logging.root.setLevel(logging.DEBUG) 
like image 79
JS. Avatar answered Sep 22 '22 02:09

JS.