python logger logging same entry numerous times

Question:

I have a such logger initializing function:

def generate_logger():
    import logging
    LOG_FILENAME = os.path.join(PROJECT_DIR, "mylog.log")
    FORMAT = "%(asctime)s : %(message)s"
    logger = logging.getLogger()
    logger.setLevel(logging.INFO)
    fh = logging.FileHandler(LOG_FILENAME)
    formatter = logging.Formatter(FORMAT)
    fh.setFormatter(formatter)
    logger.addHandler(fh)
    return logger

And at some part of my code I have such exception catching:

logger = generate_logger()
except AttributeError:
    logger.error('Opps we got an error')

Weirdly I get same error written 2 times and it can be caugh only once, once I change logger.error('Opps we got an error') with print "test", I get "test" printed once.

What can be the problem and the solution?

Asked By: Hellnar

||

Answers:

You probably have two handlers going to the same resulting log.

How many handlers are you creating? How many times are you executing generate_logger? Each time you execute generate_logger you’ll create another handler to the same file, leading to potential duplication.

Answered By: S.Lott

I think you’re probably getting two handlers added to the logger somehow. Perhaps at some point an implicit handler is being added.

Answered By: Simon Hibbs

You are adding a new FileHandler to the root logger every time you call that function: the call to logger.getLogger() without a name argument returns the same logger object every time.

You should call generate_logger() only once and then simply get the same logger object by calling logger.getLogger():

generate_logger()

# .... some time later

log = logger.getLogger()
except AttributeError:
   log.error('Opps we got an error')

(note that you do not need generate_logger() to return a value now)

Answered By: Stijn Hoop

I also faced the same problem and came across this page. Yes, I was also creating multiple handlers. In generate_logger(), you can check if there’s any other handlers and delete them.

def generate_logger():
    import logging
    LOG_FILENAME = os.path.join(PROJECT_DIR, "mylog.log")
    FORMAT = "%(asctime)s : %(message)s"
    logger = logging.getLogger()
    logger.setLevel(logging.INFO)
    # Reset the logger.handlers if it already exists.
    if logger.handlers:
        logger.handlers = []
    fh = logging.FileHandler(LOG_FILENAME)
    formatter = logging.Formatter(FORMAT)
    fh.setFormatter(formatter)
    logger.addHandler(fh)
    return logger
Answered By: mohi666

use can use singleton design pattern for this:

43 class Singleton(type):
44 “””
45 Define an Instance operation that lets clients access its unique
46 instance.
47 “””
48
49 def init(cls, name, bases, attrs, **kwargs):
50 super().init(name, bases, attrs)
51 cls._instance = None
52
53 def call(cls, *args, **kwargs):
54 if cls._instance is None:
55 cls._instance = super().call(*args, **kwargs)
56 return cls._instance
57
58
59
60 def _setup_logger(name, log_file, level=logging.INFO):
61 “””Function setup as many loggers as you want”””
62
63 handler = logging.FileHandler(log_file)
64 handler.setFormatter(formatter)
65 logger = logging.getLogger(name)
66 logger.setLevel(level)
67 logger.addHandler(handler)
68
69 return logger
70
71 class Logger(metaclass=Singleton):
72
73 def init(self, file_name, level):
74 if not (isinstance(file_name, str) and
75 isinstance(level, int)):
76 raise ValueError(“Invalid Args”)
77
78 self.log_inf = _setup_logger(‘inf’, file_name+’.inf’, level)
79 self.log_err = _setup_logger(‘err’, file_name+’.err’, level)

Answered By: Ankit Gupta