Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

InterceptHandler does not use name #1271

Open
jonashaag opened this issue Jan 9, 2025 · 1 comment
Open

InterceptHandler does not use name #1271

jonashaag opened this issue Jan 9, 2025 · 1 comment
Labels
enhancement Improvement to an already existing feature

Comments

@jonashaag
Copy link
Contributor

import inspect
import logging

from loguru import logger

class InterceptHandler(logging.Handler):
    def emit(self, record: logging.LogRecord) -> None:
        # Get corresponding Loguru level if it exists.
        try:
            level: str | int = logger.level(record.levelname).name
        except ValueError:
            level = record.levelno

        # Find caller from where originated the logged message.
        frame, depth = inspect.currentframe(), 0
        while frame:
            filename = frame.f_code.co_filename
            is_logging = filename == logging.__file__
            is_frozen = "importlib" in filename and "_bootstrap" in filename
            if depth > 0 and not (is_logging or is_frozen):
                break
            frame = frame.f_back
            depth += 1

        logger.opt(depth=depth, exception=record.exc_info).log(level, record.getMessage())

logging.basicConfig(handlers=[InterceptHandler()], level=0, force=True)

###

standard_logger = logging.getLogger("hi")


def test():
    standard_logger.info("Hello, World!")

test()
$ python t.py
2025-01-09 14:12:25.128 | INFO     | __main__:test:33 - Hello, World!

With

logging.basicConfig(level="INFO")

instead, we get:

$ python t.py
INFO:hi:Hello, World!
@Delgan
Copy link
Owner

Delgan commented Jan 13, 2025

Hey @jonashaag, thanks for the example.

I'd say it was originally kind of by design or technical limitation at least. Contrary to the standard logging module, Loguru does not require the logger to be named. Instead, it generates the name attribute from the global __name__ variable.

When crafting the InterceptHandler recipe, since there is no makeRecord() equivalent, the canonical approach is to use opt(depth=...) so that Loguru can retrieve the correct stack frame and extract the data from it. It behaves just as if the Loguru's logger were called directly. However, this implies that the original logger's name gets replaced with the module's __name__.

We could update the recipe and call patch() maybe, but it would be sub-optimal since patching is applied after filtering by enable() and disable().

However, I agree that the current implementation is possibly surprising and less convenient. I think when implementing the future logger.bridge(), we could automatically re-use the logger's name instead of reaching for the __name__. Off the top of my head, I don't think it'll cause any downside.

@Delgan Delgan added the enhancement Improvement to an already existing feature label Jan 13, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement Improvement to an already existing feature
Projects
None yet
Development

No branches or pull requests

2 participants