I have three Python modules: one contains an (abstract) parent class, and two contain classes implementing this parent class. Parent class has some concrete and some abstract methods, it looks like this:
moduleA:
from abc import ABC, abstractmethod
import logging
class Parent(ABC):
def __init__(self):
logger.info("Hello world from base class!")
def concreteMethod(self, something):
return something
@abstractmethod
def additionalMethod(self, something):
"""it needs to be implemented"""
moduleB:
import logging
from moduleA import Parent
logger = logging.getLogger("b_logger")
fh = logging.FileHandler('b_logger.log')
fh.setLevel(logging.DEBUG)
logger.addHandler(fh)
class ChildB(Parent):
def __init__(self):
super().__init__()
def additionalMethod(self):
logger.info("Hello world from B")
moduleC:
import logging
from moduleA import Parent
logger = logging.getLogger("c_logger")
fh = logging.FileHandler('c_logger.log')
fh.setLevel(logging.DEBUG)
logger.addHandler(fh)
class ChildC(Parent):
def __init__(self):
super().__init__()
def additionalMethod(self):
logger.info("Hello world from C")
Now if I decide to run:
from moduleB import ChildB
from moduleC import ChildC
B = ChildB()
B.additionalMethod()
C = ChildC()
C.additionalMethod()
I want to have two log files, each with one line from the parent class, and one from the child class.
My problem is, how do I configure the parent class logger to log into the child class' log file (not to its own)?
If you want a subclass to determine the logger, then you'd have to make the logger an attribute of the subclasses. The ABC could document this requirement with an abstract property:
class Parent(ABC):
def __init__(self):
self.logger.info("Hello world from base class!")
@property
@abstractmethod
def logger(self):
"""A logger object (can be a class attribute) to log messages to."""
def concreteMethod(self, something):
return something
@abstractmethod
def additionalMethod(self, something):
"""it needs to be implemented"""
then set the logger attribute on your child classes.
If you need the logger to be a module global, then the name logger can make it difficult to reuse the same object as a class attribute. You can work around this by using a different name for the class attribute (so not Parent.logger but something else), or by adding an alias for the logger in the module:
logger = b_logger = logging.getLogger("b_logger")
class ChildB(Parent):
logger = b_logger
def additionalMethod(self):
self.logger.info("Hello world from B")
The additionalMethod() method above uses the class attribute, but you are of course free to use the global names logger or b_logger too. Using self.logger would allow for further subclasses to change the logger reference again.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With