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
How to create logger with specific name? #204
Comments
Loguru only uses one global "anonymous" It still possible to from loguru import logger
def sink(message):
record = message.record
if record.get("name") == "your_named_logger":
print("Log comes from your named logger")
logger = logger.bind(name="your_named_logger")
logger.info("A logger message") |
Thanks for the quick response. If to write this
then will be error |
Also, why
Why print twice? |
This happens when Loguru is used with a If you plan to use
It doesn't, all loggers share the same set of handlers. It should not be printed twice. Actually, when I tried your code on my computer, it was not printed twice, so there is probably a typo somewhere else in your code. |
@heckad Oh, ok sorry, so this is the expected behavior then. I thought you was saying the same message was printed twice (which would have resulted in four messages overall). So, as I said, all loggers share the same set of handlers. This means when you call You can use If you really need to use two different |
Maybe add a check on exist in name in |
Using Maybe I could add a check in the Loguru loguru/loguru/_simple_sinks.py Lines 43 to 60 in 3b66fb5
However, this will add an extra runtime check each time a message is logged, I'm not sure it's worth it. |
Why not add the ability to customise logger name? |
Because It's part of Loguru's design: you only have to take care of your handlers, the |
I use |
That's the purpose of logger.add(sys.stderr)
logger.add("events.log", filter=lambda rec: "event" in rec["extra"])
logger.info("Some message") # Only logged to stderr
logger.bind(event=True).info("Some event") # Logged to 'events.log' too |
@heckad Are you ok with the provided workaround? I don't think I should modify API regarding logger names at that point. |
Yes, we create event_logger like |
Fine, that's the standard way to use named logger with Loguru. I'm closing this issue, then. 👍 |
I was trying to figure out the way to change a name of the record, stumbled upon this issue and drowned in frustration, since there's basically no way mentioned here. I was about to monkeypatch TL;DR:from loguru import logger
custom_logger = logger.patch(lambda record: record.update(name="custom.name"))
custom_logger.info("The name is honored") 2022-08-24 06:09:36.561 | INFO | custom.logger.name:<module>:5 - The name is honored. To address out of place import sys
from typing import TYPE_CHECKING
from loguru import logger
if TYPE_CHECKING:
from loguru import Record
def formatter(record: "Record"):
if record["name"] in sys.modules:
# this format will only makes sense if name is a module name
name_fmt = "<cyan>{name}</cyan>:<cyan>{function}</cyan>:<cyan>{line}</cyan>"
else:
# fallback format for custom names
name_fmt = "<cyan>{name}</cyan>"
return (
"<green>{time:YYYY-MM-DD HH:mm:ss.SSS}</green> | "
"<level>{level: <8}</level> | "
f"{name_fmt} - <level>{{message}}</level>"
"\n"
)
logger.remove()
logger.add(sys.stderr, format=formatter)
custom_logger = logger.patch(lambda record: record.update(name="custom.name"))
custom_logger.info("The name is honored") 2022-08-24 06:10:37.694 | INFO | custom.logger.name - The name is honored. Why not extra?Storing a custom name in extra and then choosing it instead of record name in custom formatter is an option, but not an ideal one: if extra is used in format like Real usecaseAn import logging
from loguru import logger
class InterceptHandler(logging.Handler):
def __init__(self, name: str = None) -> None:
if name is not None:
self._logger = logger.patch(lambda record: record.update(name=name))
else:
self._logger = logger
super().__init__()
def emit(self, record):
# Get corresponding Loguru level if it exists
try:
level = logger.level(record.levelname).name
except ValueError:
level = record.levelno
# Find caller from where originated the logged message
frame, depth = logging.currentframe(), 2
while frame.f_code.co_filename == logging.__file__:
frame = frame.f_back
depth += 1
self._logger.opt(depth=depth, exception=record.exc_info).log(
level, record.getMessage()
)
def init_logging():
logging.basicConfig(handlers=[InterceptHandler()], level=0)
for stdlib_logger, loguru_handler in (
(logging.getLogger(name), InterceptHandler(name))
for name in logging.root.manager.loggerDict
):
stdlib_logger.handlers = [loguru_handler]
stdlib_logger.propagate = False
init_logging()
logger.add("access.log", filter=lambda record: record["name"] == "uvicorn.access") Can we make this easier?It's a shame that setting up unified logging while retaining original loggers names is such a non-trivial task that requires lots of digging and figuring out luguru and logging quirks. Especially when loguru promises to make logging (stupidly) simple. I think some version of code above should be included in the library and available just via That's for another issue, though. |
@Bobronium I'm thinking about a way to simplify interfacing with standard |
I want to create a particular logger for logging events. How to do it?
The text was updated successfully, but these errors were encountered: