Delgan / loguru

Python logging made (stupidly) simple
MIT License
19.6k stars 694 forks source link

Using custom logger across multiple modules #1162

Closed EtagiBI closed 2 months ago

EtagiBI commented 3 months ago

Hello,

I have a programme with a bunch of modules. In the main module a have a custom logger:

    from loguru import logger

    fmt = "[{time}] [{level}] - {extra} {name}:{function}:{line} - {message}"
    logger.remove()
    logger.add(format=fmt, sink="path/to/file")
    custom_logger = logger.bind(param_1=var_1, param_2=var_2)

I want to use my custom logger to catch all errors within all modules. For base logger I could just import logger in all modules and then use decorarator @logger.catch for all functions. What would be the best practice for custom logger? Should I pass it as the argument to submodules' functions and then explicitly call custom_logger.error() within exceptblocks?

    from loguru import logger

    import submodule_1

    fmt = "[{time}] [{level}] - {extra} {name}:{function}:{line} - {message}"
    logger.remove()
    logger.add(format=fmt, sink="path/to/file")
    custom_logger = logger.bind(param_1=var_1, param_2=var_2)
    submodule_1.run(custom_logger)
Delgan commented 3 months ago

Hi @EtagiBI.

Is your custom_logger dedicated solely to catching exceptions, or does it have other uses?

Depending on your use case, you may setup your custom parameters globally using configure():

logger.configure(extra={"param_1": var_1, "param_2": var_2})

Then, the parameters will appear in the logged message even when you use the base logger from your modules.

Another alternative is to dynamically patch() the record entries if there is an exception:

def patcher(record):
    if record["exception"] is not None:
        record["extra"].update(param_1=var_1, param_2=var_2)

logger.configure(patcher=patcher)

Again, the advantage is that you can directly use the base logger in all your modules.

Otherwise, if you need to give specific access to custom_logger, the best practice is as you suggested to pass it as an argument of your functions, or to define it in a specific module and then import it in your modules:

from my_logging_config import custom_logger

@custom_logger.catch
def my_func():
    ...
EtagiBI commented 2 months ago

Is your custom_logger dedicated solely to catching exceptions, or does it have other uses?

Yes, so I'll gladly use the proposed approach with logger.configure. Thank you for the thorough explanation!