skip to Main Content

For some reason my Python logger does not want to recognize microseconds format.

import logging, io

stream = io.StringIO()
logger = logging.getLogger("TestLogger")
logger.setLevel(logging.INFO)
logger.propagate = False
log_handler = logging.StreamHandler(stream)
log_format = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s',"%Y-%m-%d %H:%M:%S.%f %Z")
log_handler.setFormatter(log_format)
logger.addHandler(log_handler)

logger.info("This is test info log")
print(stream.getvalue())

It returns:

2023-01-06 18:52:34.%f UTC - TestLogger - INFO - This is test info log

Why are microseconds missing?

Update

I am running
Python 3.10.4
Distributor ID: Debian
Description: Debian GNU/Linux 11 (bullseye)
Release: 11
Codename: bullseye

2

Answers


  1. The issue is that the formatTime method uses time.strptime to format the current time.time(), but since struct_time has no information about milliseconds and microseconds the formatter ignores the %f.

    Also, note that the LogRecord calculates the milliseconds separately and stores them in another variable named msecs

    To get what you’re looking for we need a custom version of the Formatter class that uses a different converter than time.localtime and is able to interpret the microseconds:

    
    from datetime import datetime
    
    class MyFormatter(logging.Formatter):
        def formatTime(self, record, datefmt=None):
            if not datefmt:
                return super().formatTime(record, datefmt=datefmt)
    
            return datetime.fromtimestamp(record.created).astimezone().strftime(datefmt)
    
    
    ...
    log_format = MyFormatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s', "%Y-%m-%d %H:%M:%S.%f %Z")
    ...
    

    Should output:

    2023-01-06 17:47:54.828521 EST - TestLogger - INFO - This is test info log

    Login or Signup to reply.
  2. I found that the answer given by Ashwini Chaudhary to not be applicable for me and found a slightly simpler solution in creating a function with the formatting as done with datetime and changing the value of the logging.Formatter.formatTime method to this instead i.e.:

    def _formatTime(self, record,  datefmt: str = None) -> str:
        return datetime.datetime.fromtimestamp(record.created).astimezone().strftime(datefmt)
    
    log_format = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s',"%Y-%m-%d %H:%M:%S.%f %Z")
    
    logging.Formatter.formatTime = _formatTime
    

    And then generating your logger as normal

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search