Source code for gale.log.config

"""
This file contains configure (sets up the console/file handlers, or
lets a game override them), get_logger (returns a named logger,
auto-configuring with the defaults on first use), and add_handler/
remove_handler for attaching extra destinations on top.

Author: Alejandro Mujica (aledrums@gmail.com)
"""

import logging
from typing import Optional

from .level import LogLevel

_ROOT_LOGGER_NAME: str = "gale"
_DEFAULT_LOG_FILE: str = "gale.log"
_FORMAT: str = "%(asctime)s [%(levelname)s] %(name)s: %(message)s"

_configured: bool = False


[docs] def configure( level: int = LogLevel.INFO, log_file: Optional[str] = _DEFAULT_LOG_FILE, console: bool = True, ) -> None: """ Set up gale's default logging: a console handler and/or a plain-text file handler. Call this once, as early as convenient (get_logger auto-configures with these same defaults on first use if you never call this explicitly, so calling it is only needed to override the defaults). Extra "strategies" — where else records should go, such as a Graylog server — are added on top of whatever this sets up, with add_handler; calling configure again replaces the console/file handlers but leaves any handler added through add_handler alone. :param level: The minimum severity to emit, one of the LogLevel constants. The default value is LogLevel.INFO. :param log_file: Path to the plain-text log file to write to. The default value is "gale.log". Pass None to disable file logging. :param console: Whether to also print log records to the terminal. The default value is True. """ logger = _root_logger() logger.setLevel(level) # Otherwise, if the embedding application also configures # Python's root logger (e.g. via logging.basicConfig()), every # record would be emitted twice: once by our own handlers, once # by the root's. logger.propagate = False for handler in list(logger.handlers): if getattr(handler, "_gale_default", False): logger.removeHandler(handler) formatter = logging.Formatter(_FORMAT) if console: console_handler = logging.StreamHandler() console_handler.setFormatter(formatter) console_handler._gale_default = True logger.addHandler(console_handler) if log_file is not None: file_handler = logging.FileHandler(log_file, encoding="utf-8") file_handler.setFormatter(formatter) file_handler._gale_default = True logger.addHandler(file_handler) global _configured _configured = True
[docs] def get_logger(name: Optional[str] = None) -> logging.Logger: """ :param name: A dotted name for the logger, nested under gale's own (e.g. "space_trip.player" becomes "gale.space_trip.player"). The default value is None, returning gale's own top-level logger. :returns: A standard library Logger, so it composes with anything else that already understands logging.Logger. Auto-configures with configure()'s defaults on first use if configure() was never called explicitly. """ if not _configured: configure() if name is None: return _root_logger() return logging.getLogger(f"{_ROOT_LOGGER_NAME}.{name}")
[docs] def add_handler(handler: logging.Handler) -> None: """ Attach an additional handler — a strategy for where log records should also go, such as a GraylogHandler — to gale's logger, on top of whatever configure() set up. :param handler: The handler to add. """ get_logger().addHandler(handler)
[docs] def remove_handler(handler: logging.Handler) -> None: """ :param handler: The handler to remove, previously passed to add_handler. """ get_logger().removeHandler(handler)
def _root_logger() -> logging.Logger: return logging.getLogger(_ROOT_LOGGER_NAME)