Skip to content

academy.logging.configs.file

FileLogging

FileLogging(
    *,
    logfile: str | Path,
    level: int | str = INFO,
    extra: int = False
)

Bases: LogConfig

Configures logging to a file.

Source code in academy/logging/configs/file.py
def __init__(
    self,
    *,
    logfile: str | pathlib.Path,
    level: int | str = logging.INFO,
    extra: int = False,
) -> None:
    super().__init__()
    self.logfile = logfile
    self.level = level
    self.extra = extra

init_logging

init_logging() -> Callable[[], None]

Initialize logging to file.

Source code in academy/logging/configs/file.py
def init_logging(self) -> Callable[[], None]:
    """Initialize logging to file."""
    path = pathlib.Path(self.logfile)
    path.parent.mkdir(parents=True, exist_ok=True)
    file_handler = logging.FileHandler(path)
    file_handler.setFormatter(
        _Formatter(color=False, extra=self.extra),
    )
    file_handler.setLevel(self.level)
    if self.extra:
        file_handler.addFilter(_os_thread_filter)

    root_logger = logging.getLogger()
    root_logger.addHandler(file_handler)

    # if the root logger is not going to log at this level, reconfigure it
    # to do so. (smaller log levels = more logging)
    # for example, by default the root logger logs at level 30 WARNING,
    # which means INFO (20) logs will not be recorded. But implicitly
    # if the user is asking for INFO logs, we should provide INFO logs.
    root_logger.level = min(root_logger.level, file_handler.level)

    logging.captureWarnings(True)

    logger.info(
        'Configured logger (file-level=%s)',
        logging.getLevelName(self.level)
        if isinstance(self.level, int)
        else self.level,
    )
    file_handler.flush()

    def uninitialize_callback() -> None:
        root_logger.removeHandler(file_handler)
        file_handler.close()

    return uninitialize_callback