2

I have Four files,

  • Main.py
  • A.py
  • B.py
  • Log_System

i am using main to use functions of A.py and B.py, so now i have to log all the information when ever i call them.

so i wrote a script called log_system to create log handler for each script file such as A.py, B.py

import logging

def fetchLogger(name="None") :
    logger = logging.getLogger(__name__)
    logger.setLevel(logging.DEBUG)

    if (name == "None"):
        #create File for Log
        handler = logging.FileHandler('./engine_log/Generic.log')
        handler.setLevel(logging.DEBUG)
        #log format 
        formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
        handler.setFormatter(formatter)

        #adding the handler to Logging System
        logger.addHandler(handler)
    else: 
        #create File for Log
        handler = logging.FileHandler('./engine_log/'+str(name))
        handler.setLevel(logging.DEBUG)
        #log format 
        formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
        handler.setFormatter(formatter)
        #adding the handler to Logging System
        logger.addHandler(handler)
    return logger

so if i want to use logging in script file A.py, i would write these line:

import log_system 
"""Log System Building """
file_name =  'A.py'
logger = log_system.fetchLogger(file_name)

def hello():
    try:
        logger.info("excuting Hello")
    except: 
        logger.debug("something went wrong in hello")

but my log files

2017-10-18 14:59:28,695 - log_system - INFO - A.py-excuting Hello
2017-10-18 14:59:28,695 - log_system - INFO - A.py-excuting Hello
2017-10-18 14:59:28,695 - log_system - INFO - A.py-excuting Hello
2017-10-18 14:59:28,695 - log_system - INFO - A.py-excuting Hello
2017-10-18 14:59:28,695 - log_system - INFO - A.py-excuting Hello

it is repeating the log many times.... so what should i do ??

solution

logger = logging.getLogger(name)

if logger.hasHandlers(): 
    logger.handlers = []

logger.setLevel(logging.DEBUG)

#create File for Log
handler = logging.FileHandler('./engine_log/'+str(name))
handler.setLevel(logging.DEBUG)
#log format 
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
handler.setFormatter(formatter)
#adding the handler to Logging System
logger.addHandler(handler)

return logger

this is how i changed my log_system code, so i just emptied the Handler list if i had created an log handler already so that it does not create duplicate records.

khex
  • 2,778
  • 6
  • 32
  • 56
  • i think the most robust method is still just manually duplicating your message both to print statements and logger.info(); explicit is better than implicit – ivan866 Oct 30 '22 at 21:18

2 Answers2

12

Every time fetch_logger is called it adds a new FileHandler to the logger. Each FileHandler writes to the log file, resulting in the repeating output in the file.

One solution is to call the logger's hasHandlers method. This will return True if any handlers have been configured on the logger, and then you can delete them.

def fetchLogger(name="None") :
    logger = logging.getLogger(__name__)
    if logger.hasHandlers():
        # Logger is already configured, remove all handlers
        logger.handlers = []
    # Configure the logger as before.
    ...
snakecharmerb
  • 47,570
  • 11
  • 100
  • 153
  • This is enlightening and finally solved my issue with these duplicate things. ``` if logger.hasHandlers(): # Logger is already configured, remove all handlers logger.handlers = [] ``` Appreciate the share and surprised you don't have more upvotes. – Mike R May 23 '22 at 11:34
2

There may be another cause for duplicates when using the __name__ variable as the logger name.
The logger assumes that dots in the name indicate a parent-child relatationship. If you already created a logger from a module higher in the tree, it is also called to handle the logging.

So if you first logger = logger.get_logger(__name__) in module 'foo' and add handlers to it,
then another_logger = logger.get_logger(__name__) in module 'foo.bar' and add handlers to it,
you have created a parent and a child.

Using another_logger.info('Some text') in the foo.bar module will result in executing the handlers of the 'foo.bar' handler first and then the same message by the 'foo' handler.