Source code for thesis.core.logging.handlers
"""
Custom log handlers for specialized logging needs.
This module provides custom handlers for specific logging scenarios
in medical imaging pipelines, such as patient-specific logs, step logs,
and performance tracking.
"""
import logging as _stdlib_logging
from pathlib import Path
from loguru import logger
__all__ = [
"InterceptHandler",
]
[docs]
class InterceptHandler(_stdlib_logging.Handler):
"""
Intercepts stdlib logging records and forwards them to loguru.
Install once via logging.basicConfig(handlers=[InterceptHandler()], level=0, force=True)
to route all third-party library logs (e.g. Nipype, FSL wrappers) through
loguru's formatting.
"""
[docs]
def emit(self, record: _stdlib_logging.LogRecord) -> None:
try:
level = logger.level(record.levelname).name
except ValueError:
level = str(record.levelno) # fallback to int level as string
# Walk up the call stack to find the real caller (past this handler and
# stdlib logging internals like logging.callHandlers).
handler_file = str(Path(__file__).resolve())
stdlib_logging_dir = str(Path(_stdlib_logging.__file__).resolve().parent)
frame, depth = _stdlib_logging.currentframe(), 2
while frame:
frame_path = str(Path(frame.f_code.co_filename).resolve())
in_handler = frame_path == handler_file
in_stdlib_logging = frame_path.startswith(stdlib_logging_dir)
if not (in_handler or in_stdlib_logging):
break
frame = frame.f_back # type: ignore[assignment]
depth += 1
def _patch_record(log_record: dict) -> None:
log_record["name"] = record.name
log_record["function"] = record.funcName
log_record["line"] = record.lineno
log_record["module"] = record.module
patched_logger = logger.patch(_patch_record) # type: ignore[arg-type]
patched_logger.opt(depth=depth, exception=record.exc_info).log(level, record.getMessage())