Source code for ooai_llm.logging
"""Logging helpers for ``ooai_llm``.
Purpose:
Provide one small logging facade that prefers ``ultilog`` when installed
and falls back to standard-library logging when the optional dependency is
absent.
"""
from __future__ import annotations
from collections.abc import Iterator
from contextlib import contextmanager
import importlib
import logging as stdlib_logging
from typing import Any, Literal
[docs]
LoggingPreset = Literal["dev", "test", "prod"]
[docs]
LoggingMode = Literal["rich", "plain", "json"]
def _load_ultilog() -> Any | None:
"""Return the optional ``ultilog`` module when available."""
try:
return importlib.import_module("ultilog")
except ImportError:
return None
[docs]
def get_logger(name: str | None = None) -> stdlib_logging.Logger:
"""Return a logger from ``ultilog`` when available, else stdlib logging."""
ultilog = _load_ultilog()
if ultilog is not None:
get_ultilog_logger = getattr(ultilog, "get_logger", None)
if callable(get_ultilog_logger):
return get_ultilog_logger(name) if name is not None else get_ultilog_logger()
return stdlib_logging.getLogger(name or "ooai_llm")
@contextmanager
[docs]
def logging_context(**fields: Any) -> Iterator[None]:
"""Bind contextual logging fields when ``ultilog`` supports it."""
ultilog = _load_ultilog()
if ultilog is not None:
bind_context = getattr(ultilog, "logging_context", None)
if callable(bind_context):
with bind_context(**fields):
yield
return
yield
[docs]
def log_event(
logger: stdlib_logging.Logger,
event: str,
*,
level: str = "debug",
**fields: Any,
) -> None:
"""Emit a structured-ish log event without assuming a specific backend."""
method = getattr(logger, level, logger.debug)
extra = {"ooai_event": event}
extra.update({f"ooai_{key}": value for key, value in fields.items()})
try:
method(event, extra=extra)
except Exception: # pragma: no cover - logging should never break callers
method("%s %s", event, fields)