0

I have a library in which I am creating the logger as a class attribute

The entry point class accepts handlers and applies adds them to the root logger:

class Parser:
    def __init__(self, handlers):
        for hdlr in handlers:
            logging.root.addHandler(hdlr)

Now this works if my internal classes initialise the logger like this:

class Event(abc.ABC):
    def __init__(self):
        self._log = logging.getLogger(__name__)

However, this is no use as the logs don't show the class name. So I tried this:

class Event(abc.ABC):
    def __init__(self):
        self._log = logging.getLogger(self.__class__.__name__)

This would allow me to see the class name in the logs for the subclasses.

Alas, this doesn't work. This answer will not work for me probably, since Event objects are constructed after the __init__ method of Parser is finished (and hence the loggers they use), so logging.root.manager.loggerDict would still be empty.

This doesn't work either

class Parser:
    def __init__(self, handlers):
        for hdlr in handlers:
            logging.root.addHandler(hdlr)
            for cls in Event.__subclasses__():
                logging.getLogger(cls.__name__).addHandler(handler)

EDIT: This is my __init__.py at the package root. I doubt it is any use. But I don't know what else to give, I have already provided all the logging code above.

"""
Attributions:
    Logger decorators:  https://stackoverflow.com/a/7004565
"""

import functools
import logging

class WrapperFormatter(logging.Formatter):
    def format(self, record: logging.LogRecord):
        if hasattr(record, "name_override"):
            record.funcName = record.name_override
        return super().format(record)


logfmt = "[%(levelname)s] %(name)s <%(module)s.%(funcName)s>  %(message)s"
logger = logging.getLogger(__name__)
handler = logging.NullHandler()
logger.setLevel(logging.DEBUG)
handler.setLevel(logging.DEBUG)
handler.setFormatter(WrapperFormatter(logfmt))
logger.addHandler(handler)


def called(func):
    @functools.wraps(func)
    def wrapper(*a, **kw):
        log = "called"
        if a:
            log += f" with {(repr(arg) for arg in a)}"
        logger.debug(log, extra={"name_override": func.__name__})
        return func(*a, **kw)
    return wrapper

I have a feeling that I am doing this the wrong way.

demberto
  • 489
  • 5
  • 15
  • I can't tell from your question what it is that doesn't work after the name change. Can you provide a minimal reproducible example? – blues Oct 19 '21 at 14:49
  • @blues I have added code from `__init__.py` at package root. I hope it helps – demberto Oct 20 '21 at 10:34

0 Answers0