Source code for thinlog.log
"""Logger adapter that converts keyword arguments into *extra* fields."""
import logging
from collections.abc import MutableMapping
from typing import Any
[docs]
class KeywordFriendlyLogger(logging.LoggerAdapter[logging.Logger]):
"""A :class:`logging.LoggerAdapter` that passes arbitrary keyword arguments as *extra* fields.
Standard :mod:`logging` requires extra data to be wrapped in an ``extra``
dict. :class:`KeywordFriendlyLogger` lets callers pass keyword arguments
directly -- they are automatically moved into *extra* so that filters,
formatters, and handlers can access them as record attributes.
:param logger: The underlying :class:`logging.Logger` to adapt.
:param extra: Optional default extra fields attached to every record.
"""
ignored_meta_keys = ("exc_info", "stack_info", "stacklevel")
def __init__(self, logger: logging.Logger, extra: dict[str, Any] | None = None) -> None:
super().__init__(logger, extra or {})
[docs]
def process(self, msg: Any, metadata: MutableMapping[str, Any]) -> tuple[Any, MutableMapping[str, Any]]:
"""Move keyword arguments into the *extra* dict.
Keys listed in :attr:`ignored_meta_keys` are left in *metadata* so
that the standard logging machinery can handle them.
:param msg: The log message.
:param metadata: Keyword arguments passed to the logging call.
:returns: A ``(msg, metadata)`` tuple ready for the underlying logger.
"""
extra = metadata.pop("extra", {})
extra.update(self.extra)
for key, value in list(metadata.items()):
if key not in self.ignored_meta_keys:
extra[key] = metadata.pop(key)
extra["stacklevel"] = metadata.get("stacklevel", 1)
metadata["extra"] = extra
return msg, metadata