Source code for duck.logging.handler

"""
Handler module for intercepting Duck logs.
"""
import threading

from typing import Optional, Union
from collections.abc import Callable, Iterable


_HANDLER_LOCK = threading.Lock()
HANDLERS: dict[int | None, set[Callable[[int, str], None]]] = {}


[docs] def register_handler( callback: Callable[[int, str], None], levels: Optional[Union[Iterable[int], int]] = None, ): """ Register a log handler. Args: callback: The callback to register. levels: Log levels to listen for. If None or empty, listens for all levels. """ if isinstance(levels, int): levels = (levels, ) selected_levels = tuple(levels or (None,)) with _HANDLER_LOCK: for level in selected_levels: HANDLERS.setdefault(level, set()).add(callback)
[docs] def remove_handler( callback: Callable[[int, str], None], levels: Iterable[int] | None = None, ): """ Remove a registered log handler. Args: callback: The callback to remove. levels: Log levels to remove from. If None or empty, removes from all levels. """ with _HANDLER_LOCK: selected_levels = tuple(levels or HANDLERS.keys()) for level in selected_levels: handlers = HANDLERS.get(level) if not handlers: continue handlers.discard(callback) if not handlers: HANDLERS.pop(level, None)
[docs] def emit(level: int, message: str): """ Emit a log message to all matching handlers. """ with _HANDLER_LOCK: handlers = ( list(HANDLERS.get(None, ())) + list(HANDLERS.get(level, ())) ) for callback in handlers: callback(level, message)