PepperoniPizza
PepperoniPizza

Reputation: 9102

Python logging repeating lines

My issue is a design problem. I have the following Logger class:

import logging, logging.handlers

class Logger(object):
    def __init__(self, log_filename, name):
        self.LOG_FILENAME = log_filename

        logging.basicConfig(format='%(asctime)s %(message)s')
        formatter = logging.Formatter(
            '%(asctime)s - %(levelname)s - %(message)s')
        loghandler = logging.handlers.RotatingFileHandler(
            self.LOG_FILENAME)
        loghandler.setFormatter(formatter)
        self.logger = logging.getLogger(name)
        self.logger.setLevel(logging.INFO)
        self.logger.addHandler(loghandler)

    def getLogger(self):
        return self.logger

The context is the following, I have several modules that will make use of this class, every class is agnostic of the others or of the logger, so every class instantiates a new Logger class (even when they need to write to the same file), the problem is that if I have 2 classes that need to write to the same Logger, I get repeated lines, this reproduces the bug:

def a():
    log = Logger(log_filename='test.log', name='test')
    logger = log.getLogger()
    logger.info('A')

def b():
    log = Logger(log_filename='test.log', name='test')
    logger = log.getLogger()
    logger.info('B')

so if I call a() I will get what I'm expecting: 2014-12-02 10:26:40,665 - INFO - A, but if now I call b() i'll get:

2014-12-02 10:26:40,665 - INFO - A
2014-12-02 10:26:48,553 - INFO - B
2014-12-02 10:26:48,553 - INFO - B

and so on, I know Logger is a Singleton class, and the bug has to be in my Logger class, but I assumed that getLogger with the name of the logger would return the "same" logging class instance.

Upvotes: 2

Views: 863

Answers (1)

Reut Sharabani
Reut Sharabani

Reputation: 31339

Your assumption is correct and is the cause for the problem. You're adding many handlers to the same logger here:

    self.logger = logging.getLogger(name) # <-- same logger for same "name"!
    self.logger.setLevel(logging.INFO)
    self.logger.addHandler(loghandler)

With each instantiation using the same name parameter (in your case in both calls):

    # same name!
def a():
    log = Logger(log_filename='test.log', name='test')
...
def b():
    log = Logger(log_filename='test.log', name='test')

the same logger gets more handlers.

Upvotes: 4

Related Questions