Search code examples
loggingpython

Python logging.setLoggerClass() isn't


Given this bit of Python:

logging.setLoggerClass(MyLogger)    
logger = logging.getLogger()    
print(type(logger))

...and what I believe is a properly implemented MyLogger class:

class MyLogger(logging.getLoggerClass()):
    def __init__(self, name: str=os.path.basename(__file__)) -> None:
        logging.Logger.__init__(self, name=name)

I'd expect GetLogger to return an instance of MyLogger, but it doesn't:

<class 'logging.RootLogger'>

No errors or warning. It also seems that the MyLogger constructor is never being called when I make a call to logging.getLogger()

What am I doing wrong?


Solution

  • It's already too late to influence the creation of the root logger when you called setLoggerClass(...). The root logger was already instantiated, it's created at the time of executing import logging, and exists as a RootLogger instance in the logging module's namespace. That getLogger() call is just returning the existing instance.

    However, any other logger you subsequently create, e.g. logging.getLogger('mylogger'), will be an instance of your subclass. Generally you will have this at the top of your module:

    log = logging.getLogger(__name__)
    

    And this log will by a MyLogger instance.

    Now, you shouldn't really care what class the root logger is, since you don't want events handled by it anyway. However, since this is Python and we're permitted to shoot our own grandparents if we really wish to, it's possible to morph the root logger's type all the same:

    >>> root = logging.getLogger()
    >>> root.__class__ = MyLogger
    >>> root
    <MyLogger root (WARNING)>
    

    A root logger is not that different to any other logger, except that it must have a logging level. Provided you obeyed Liskov substitution principle when implementing MyLogger, this should work fine - any events that reach the root logger will be able to use MyLogger's customizations.