Source code for gd.logging

import logging
from pathlib import Path

from gd.typing import IO, Optional, Union

__all__ = (
    "enable_file_handler_for",
    "enable_stream_handler_for",
    "get_logger",
    "log",
    "setup_logging",
)

ALL_STYLES = ("%", "{", "$")

DEFAULT_LOG_FORMAT = "[{levelname}] ({asctime}) [{name}] {module}.{funcName}:{lineno}: {message}"


def get_logger(name: Optional[str] = None) -> logging.Logger:
    """Get logger by ``name``.

    Returns
    -------
    :class:`logging.Logger`
        Logger that was fetched by ``name``.
    """
    return logging.getLogger(name)


def get_module_logger() -> logging.Logger:
    return get_logger(__name__.split(".")[0])


def attempt_all_format_styles(format_string: str) -> logging.Formatter:
    """Try to create :class:`logging.Formatter` with all possible styles."""

    for style in ALL_STYLES:
        try:
            return logging.Formatter(format_string, style=style)

        except ValueError:
            pass

    else:
        raise ValueError(f"Format string {format_string!r} is invalid.")


def add_formatter_and_handler(
    logger: logging.Logger,
    handler: logging.Handler,
    level: int = logging.DEBUG,
    format_string: Optional[str] = None,
) -> None:
    """Add formatter defined by ``format_string``, and ``handler`` with ``level`` to ``logger``.

    Parameters
    ----------
    logger: :class:`logging.Logger`
        Logger to add handler and formatter to.

    handler: :class:`logging.Handler`
        Handler to add to ``logger``.

    level: :class:`int`
        Level to set in ``handler``.

    format_string: Optional[:class:`str`]
        String to use for formatter. Default is ``gd.logging.DEFAULT_LOG_FORMAT``.
    """
    if format_string is None:
        format_string = DEFAULT_LOG_FORMAT

    handler.setFormatter(attempt_all_format_styles(format_string))

    handler.setLevel(level)

    logger.addHandler(handler)


def enable_file_handler_for(
    logger: logging.Logger,
    filename: Union[Path, str],
    level: int = logging.DEBUG,
    format_string: Optional[str] = None,
) -> None:
    """Add file handler for ``logger``, with ``filename`` and formatter with ``format_string``.

    Parameters
    ----------
    logger: :class:`logging.Logger`
        Logger to add handler and formatter to.

    filename: Union[:class:`~pathlib.Path`, :class:`str`]
        File to write logs to.

    level: :class:`int`
        Level to set in the handler.

    format_string: Optional[:class:`str`]
        String to use for formatter. Default is ``gd.logging.DEFAULT_LOG_FORMAT``.
    """
    add_formatter_and_handler(
        logger=logger,
        handler=logging.FileHandler(filename),
        level=level,
        format_string=format_string,
    )


def enable_stream_handler_for(
    logger: logging.Logger,
    stream: Optional[IO] = None,
    level: int = logging.DEBUG,
    format_string: Optional[str] = None,
) -> None:
    """Add stream handler for ``logger``, with ``stream`` and formatter with ``format_string``.

    Parameters
    ----------
    logger: :class:`logging.Logger`
        Logger to add handler and formatter to.

    stream: Optional[IO]
        Stream to write logs to. If ``None`` or not given, :data:`sys.stderr` is used.

    level: :class:`int`
        Level to set in the handler.

    format_string: Optional[:class:`str`]
        String to use for formatter. Default is ``gd.logging.DEFAULT_LOG_FORMAT``.
    """
    add_formatter_and_handler(
        logger=logger,
        handler=logging.StreamHandler(stream),
        level=level,
        format_string=format_string,
    )


[docs]def setup_logging( level: int = logging.DEBUG, format_string: Optional[str] = None, stream: Optional[IO] = None, filename: Optional[str] = None, ) -> None: """Setup logger with ``level`` and ``format_string``. Either stream handler for ``stream``, or file handler for ``filename``. Parameters ---------- level: :class:`int` Level to set in the handler. format_string: Optional[:class:`str`] String to use for formatter. Default is ``gd.logging.DEFAULT_LOG_FORMAT``. stream: Optional[IO] Stream to write logs to. If ``None`` or not given, :data:`sys.stderr` is used. filename: Union[:class:`~pathlib.Path`, :class:`str`] File to write logs to. """ if filename is None: enable_stream_handler_for( logger=log, stream=stream, level=level, format_string=format_string ) else: enable_file_handler_for( logger=log, filename=filename, level=level, format_string=format_string )
log = get_module_logger() log.setLevel(logging.DEBUG) log.addHandler(logging.NullHandler())