Reputation: 396
My class constructs a logger named after the class in init(). Now when I log a message, I get one copy of the message for every instance of the class that has been created so far. How do I avoid this duplication?
I'm also concerned that this might just be a symptom of a deeper problem - is this a wasteful approach to memory management in an application that may instantiate a few hundred classes at a time? Is there a more sensible way of handling logging across multiple classes?
While the code below is a simplistic recreation of the problem, the actual code is very modular and each class may be used in many different ways by a variety of different applications. Each class might be used as a standalone class invoked by the main() method defined with it, or it might be invoked from another class, or from one of three or four main applications. The approach to logging needs to allow for this modularity.
import logging
class person:
def __init__(self,name):
self.name = name
logger = logging.getLogger('person logger')
logger.setLevel(logging.DEBUG)
ch = logging.StreamHandler()
formatter = logging.Formatter('%(name)s - %(message)s')
ch.setFormatter(formatter)
logger.addHandler(ch)
logger.info(f'{self.name} exists')
if __name__ == '__main__':
for name in ["Alice", "Bob", "Carlos"] :
a = person(name)
Expected results:
person logger - Alice exists
person logger - Bob exists
person logger - Carlos exists
Actual results:
person logger - Alice exists
person logger - Bob exists
person logger - Bob exists
person logger - Carlos exists
person logger - Carlos exists
person logger - Carlos exists
Upvotes: 3
Views: 290
Reputation: 20224
Use if logger.handlers
to check if there have already been handlers. Or you are adding handler every time you create that person
object.
Basically:
import logging
class person:
def __init__(self,name):
self.name = name
logger = logging.getLogger('person logger')
logger.setLevel(logging.DEBUG)
if not logger.handlers:
ch = logging.StreamHandler()
formatter = logging.Formatter('%(name)s - %(message)s')
ch.setFormatter(formatter)
logger.addHandler(ch)
logger.info(f'{self.name} exists')
if __name__ == '__main__':
for name in ["Alice", "Bob", "Carlos"] :
a = person(name)
Further, mostly we don't create a logger for a class but for a module.
For a huge project, create a log_helper
module which may contain initialization function:
def getLogger(name):
logger = logging.getLogger(name)
# do some initialization...
# like adding handlers
return logger
And get logger at the top of each module:
# person.py Module person
import log_helper
logger = log_helper.getLogger("person") # or whatever you want
# just use this logger...
Upvotes: 4