pythonloggingpython-logging

Logging always prints an extra message on console


I have some code that works but does things that I don't understand. This code uses the logging module. The problem is that when I run this script there is always (in addition to the normal Stream Log) a line on the console that I don't want (the second line in the output shown at the bottom of this post).

I don't understand why this line exists and how solve this problem.

I think that problem is due to the usage of logging.basicConfig(level=logging.INFO), but I need to use it, because if I don't use it, logger.info('This is a INFO-01') doesn't work, just the level WARNING, etc.

import logging

logging.basicConfig(level=logging.INFO)

logger = logging.getLogger(__name__)

c_handler = logging.StreamHandler()
f_handler = logging.FileHandler('file07.log')
c_handler.setLevel(logging.INFO)
f_handler.setLevel(logging.INFO)

c_format = logging.Formatter('%(asctime)s - %(levelname)s - %(message)s')
f_format = logging.Formatter('%(asctime)s - %(levelname)s - %(message)s')
c_handler.setFormatter(c_format)
f_handler.setFormatter(f_format)

logger.addHandler(c_handler)
logger.addHandler(f_handler)


logger.info('This is a INFO-01')

Output:

2021-12-11 17:54:30,203 - INFO - This is a INFO-01
INFO:__main__:This is a INFO-01

Solution

  • You guessed it right. Take a look at this image from the documentation. (it's deleted and converted to a SVG available here )

    By default the propagation is True. So your logger object has a parent logger named "root".

    basicConfig essentially does basic configuration for the logging system by creating a StreamHandler with a default Formatter and adding it to the root logger.

    The 'root' is the parent of all loggers. So after your logger logger's handlers process the message, it will get handed to the parent logger's handlers, and because it has a handler now, it outputs that message for the second time with the default format.

    You can remove that because you don't need it. Don't forget to specify LEVEL for your logger: (I removed the f_handler handler in the below code)

    import logging
    
    logger = logging.getLogger(__name__)
    logger.setLevel(logging.INFO)  # <----- here
    
    c_handler = logging.StreamHandler()
    c_handler.setLevel(logging.INFO)
    
    c_format = logging.Formatter('%(asctime)s - %(levelname)s - %(message)s')
    c_handler.setFormatter(c_format)
    
    logger.addHandler(c_handler)
    
    logger.info('This is a INFO-01')