Search code examples
pythonloggingnewlinepython-logging

How to insert newline in python logging?


import logging
logging.basicConfig(level=logging.DEBUG, format='%(asctime)s %(levelname)s %(message)s', datefmt='%H:%M:%S')
logging.info('hello')
logging.warning('\n new hello')

11:15:01 INFO hello
11:16:49 WARNING
 new hello

Because the log is crowded, I want to explicitly insert a newline before asctime and levelname. Is this possible without modifying format?

I looked into logging module and googled a bit and could not find a viable way.


Solution

  • I have two solutions, the first is very easy, but the output is not very clean. The second method will produce the exact output you want, but it is a little more involved.

    Method 1

    To produce a blank line, just log an empty string with a new line:

    import logging
    logging.basicConfig(level=logging.DEBUG, format='%(asctime)s %(levelname)s %(message)s', datefmt='%H:%M:%S')
    logging.info('hello')
    logging.info('\n')
    logging.warning('new hello')
    

    The output will have an empty info line, which is not very clean:

    16:07:26 INFO hello
    16:07:26 INFO

    16:07:26 WARNING new hello

    Method 2

    In this method, I created two different handlers. The console_handler which I use most of the time. When I need a new line, I switch to a second handler, blank_handler.

    import logging
    import types
    
    def log_newline(self, how_many_lines=1):
        # Switch handler, output a blank line
        self.removeHandler(self.console_handler)
        self.addHandler(self.blank_handler)
        for i in range(how_many_lines):
            self.info('')
    
        # Switch back
        self.removeHandler(self.blank_handler)
        self.addHandler(self.console_handler)
    
    def create_logger():
        # Create a handler
        console_handler = logging.StreamHandler()
        console_handler.setLevel(logging.DEBUG)
        console_handler.setFormatter(logging.Formatter(fmt="%(name)s %(levelname)-8s: %(message)s"))
    
        # Create a "blank line" handler
        blank_handler = logging.StreamHandler()
        blank_handler.setLevel(logging.DEBUG)
        blank_handler.setFormatter(logging.Formatter(fmt=''))
    
        # Create a logger, with the previously-defined handler
        logger = logging.getLogger('logging_test')
        logger.setLevel(logging.DEBUG)
        logger.addHandler(console_handler)
    
        # Save some data and add a method to logger object
        logger.console_handler = console_handler
        logger.blank_handler = blank_handler
        logger.newline = types.MethodType(log_newline, logger)
    
        return logger
    
    if __name__ == '__main__':
        logger = create_logger()
        logger.info('Start reading database')
        logger.info('Updating records ...')
        logger.newline()
        logger.info('Finish updating records')
    

    The output is what you want to see:

    logging_test INFO    : Start reading database
    logging_test INFO    : Updating records ...
    
    logging_test INFO    : Finish updating records
    

    Discussion

    • If you can put up with the less-than-perfect output, method 1 is the way to go. It has the advantage of being simple, least amount of effort.
    • The second method does the job correctly, but it is a little involved. It creates two different handlers and switch them in order to achieve your goal.
    • Another disadvantage of using method 2 is you have to change your code by searching for logging and replacing them with logger. You must take care replacing only relevant parts and leave such text as logging.DEBUG in tact.