Strange behaviour on my logging class

2019-08-01 05:36发布

问题:

I will try to resume as much as possible. I have this class I wrote:

Logging class

import logging, logging.handlers.TimedRotatingFileHandler

class Logger(object):
    def __init__(self, log_filename):
        logging.basicConfig(format='%(asctime)s %(message)s')
        formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(message)s')
        loghandler = TimedRotatingFileHandler(
            log_filename, when="midnight", backupCount=50
        )
        loghandler.setFormatter(formatter)
        self.logger = logging.getLogger()
        self.logger.setLevel(logging.INFO)
        self.logger.addHandler(loghandler)

    def getLogger(self):
        return self.logger

It works good indeed, now the problem arises when I have a script that uses a Logger instance and within that script I instantiate a class that uses a Logger too, something like this:

Script

import ClassA

A = ClassA()
log = Logger(log_filename='script_logger.log')
logger = log.getLogger()
logger.info('Initiated Script')

while True:
    logger.info('Looping')
    A.run()

What my class looks like:

ClassA module

class ClassA(object):
    def __init__(self):
        log = Logger(log_filename='class_logger.log')
        self.logger = log.getLogger()
        self.logger.info('Started ClassA')

    def run(self):
        self.logger.info('Into method run')

Now I expect to have 2 separate log files, class_logger.log and script_logger.log that works OK, but both files have exactly the same content line by line.

So script_logger.log and class_logger.log have the following content:

Started classA
Initiated Script
Looping
Into method run
Looping
Into method run
...

Any clues ?

回答1:

The reason is the class and script have the same logger object when you do logging.getLogger(). It's a singleton. If you want different loggers then you should pass the logger name e.g logging.getLogger('logger1') Typically libraries do logging.getLogger(__name__) so that each module gets a different logger. refer http://docs.python.org/2/library/logging.html#logger-objects

I have modified your code so that it works as expected now

import logging, logging.handlers
from logging.handlers import TimedRotatingFileHandler

class Logger(object):
    def __init__(self, log_filename, name):
        logging.basicConfig(format='%(asctime)s %(message)s')
        formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(message)s')
        loghandler = TimedRotatingFileHandler(
            log_filename, when="midnight", backupCount=50
        )
        loghandler.setFormatter(formatter)
        self.logger = logging.getLogger(name)
        self.logger.setLevel(logging.INFO)
        self.logger.addHandler(loghandler)

    def getLogger(self):
        return self.logger


class ClassA(object):
    def __init__(self):
        log = Logger(log_filename='class_logger.log', name="Class")
        self.logger = log.getLogger()
        self.logger.info('Started ClassA')

    def run(self):
        self.logger.info('Into method run')


A = ClassA()
log = Logger(log_filename='script_logger.log', name="Script")
logger = log.getLogger()
logger.info('Initiated Script')

for x in range(5):
    logger.info('Looping')
    A.run()