- Fix logging_compat._log() to handle extra keyword arguments properly - Update config.py, main.py, and test_bans.py for compatibility - Update Tasks.md and runner.csx
71 lines
2.3 KiB
Python
71 lines
2.3 KiB
Python
"""Compatibility shim providing keyword-argument logging API on top of stdlib logging.
|
|
|
|
This module lets the rest of the codebase keep the keyword-argument logging
|
|
style (``log.info("event", key=value)``) while using only the Python standard
|
|
library ``logging`` module underneath.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import logging
|
|
from typing import Any
|
|
|
|
|
|
class _CompatLogger:
|
|
"""Wraps a stdlib :class:`logging.Logger` to accept keyword arguments."""
|
|
|
|
def __init__(self, logger: logging.Logger) -> None:
|
|
self._logger = logger
|
|
|
|
_STDLIB_LOG_KWARGS = frozenset(("exc_info", "extra", "stack_info", "stacklevel"))
|
|
|
|
def _log(self, level: int, event: str, **kwargs: Any) -> None:
|
|
stdlib_kwargs: dict[str, Any] = {}
|
|
for k in self._STDLIB_LOG_KWARGS:
|
|
v = kwargs.pop(k, None)
|
|
if v is not None:
|
|
stdlib_kwargs[k] = v
|
|
if kwargs:
|
|
stdlib_kwargs["extra"] = kwargs
|
|
self._logger.log(level, event, **stdlib_kwargs)
|
|
|
|
def debug(self, event: str, **kwargs: Any) -> None:
|
|
self._log(logging.DEBUG, event, **kwargs)
|
|
|
|
def info(self, event: str, **kwargs: Any) -> None:
|
|
self._log(logging.INFO, event, **kwargs)
|
|
|
|
def warning(self, event: str, **kwargs: Any) -> None:
|
|
self._log(logging.WARNING, event, **kwargs)
|
|
|
|
def warn(self, event: str, **kwargs: Any) -> None:
|
|
self._log(logging.WARNING, event, **kwargs)
|
|
|
|
def error(self, event: str, **kwargs: Any) -> None:
|
|
self._log(logging.ERROR, event, **kwargs)
|
|
|
|
def critical(self, event: str, **kwargs: Any) -> None:
|
|
self._log(logging.CRITICAL, event, **kwargs)
|
|
|
|
def exception(self, event: str, **kwargs: Any) -> None:
|
|
self._log(logging.ERROR, event, exc_info=True, **kwargs)
|
|
|
|
def bind(self, **kwargs: Any) -> "_CompatLogger":
|
|
"""Return a new logger with bound context (no-op for stdlib)."""
|
|
return self
|
|
|
|
|
|
def get_logger(name: str | None = None) -> _CompatLogger:
|
|
"""Get a compatibility logger wrapping the stdlib logger for *name*.
|
|
|
|
If *name* is ``None`` the caller's module name is used.
|
|
"""
|
|
if name is None:
|
|
import sys
|
|
|
|
# Walk up the stack to find the caller's module.
|
|
frame = sys._getframe(1)
|
|
module = frame.f_globals.get("__name__", "__main__")
|
|
name = module
|
|
return _CompatLogger(logging.getLogger(name))
|