Source code for f_lib.logging._console_handler

"""Custom console :class:`~rich.logging.RichHandler`."""

from __future__ import annotations

import logging
from typing import TYPE_CHECKING

from rich.logging import RichHandler
from rich.markup import escape
from rich.text import Text

if TYPE_CHECKING:
    from collections.abc import Callable, Iterable
    from datetime import datetime
    from types import ModuleType

    from rich.console import Console, ConsoleRenderable
    from rich.highlighter import Highlighter

    from ._fluid_log_render import FluidLogRender


[docs] class ConsoleHandler(RichHandler): """Custom console :class:`~rich.logging.RichHandler`."""
[docs] def __init__( # noqa: PLR0913 self, level: int | str = logging.NOTSET, console: Console | None = None, *, enable_link_path: bool = True, highlighter: Highlighter | None = None, keywords: list[str] | None = None, locals_max_length: int = 10, locals_max_string: int = 80, log_render_kls: type[FluidLogRender] | None = None, log_time_format: str | Callable[[datetime], Text] = "[%x %X]", markup: bool = False, name: str = "rich.console", omit_repeated_times: bool = True, rich_tracebacks: bool = False, show_level: bool = True, show_path: bool = True, show_time: bool = True, tracebacks_code_width: int = 88, tracebacks_extra_lines: int = 3, tracebacks_max_frames: int = 100, tracebacks_show_locals: bool = False, tracebacks_suppress: Iterable[str | ModuleType] = (), tracebacks_theme: str | None = None, tracebacks_width: int | None = None, tracebacks_word_wrap: bool = True, **kwargs: object, ) -> None: """Instantiate class. Args: level: Log level. console: Optional console instance to write logs. Default will use a global console instance writing to stdout. enable_link_path: Enable terminal link of path column to file. highlighter: Highlighter to style log messages, or None to use ReprHighlighter. keywords: List of words to highlight instead of ``RichHandler.KEYWORDS``. locals_max_length: Maximum length of containers before abbreviating, or None for no abbreviation. locals_max_string: Maximum length of string before truncating, or None to disable. log_render_kls: Custom log rendering class. If not provided, will use the one provided by rich. log_time_format: If ``log_time`` is enabled, either string for strftime or callable that formats the time. markup: Enable console markup in log messages. name: Name of the handler. Can be used to check for existence. omit_repeated_times: Omit repetition of the same time. rich_tracebacks: Enable rich tracebacks with syntax highlighting and formatting. show_level: Show a column for the level. show_path: Show the path to the original log call. show_time: Show a column for the time. tracebacks_code_width: Number of code characters used to render tracebacks, or None for full width. tracebacks_extra_lines: Additional lines of code to render tracebacks, or None for full width. tracebacks_max_frames: Optional maximum number of frames returned by traceback. tracebacks_show_locals: Enable display of locals in tracebacks. tracebacks_suppress: Optional sequence of modules or paths to exclude from traceback. tracebacks_theme: Override pygments theme used in traceback. tracebacks_width: Number of characters used to render tracebacks, or None for full width. tracebacks_word_wrap: Enable word wrapping of long tracebacks lines. **kwargs: Additional options added to :class:`~rich.logging.RichHandler` that are not explicitly listed here. This is to provide support for future releases without requiring a new release here to support it. """ super().__init__( level, console, enable_link_path=enable_link_path, highlighter=highlighter, keywords=keywords, locals_max_length=locals_max_length, locals_max_string=locals_max_string, log_time_format=log_time_format, markup=markup, omit_repeated_times=omit_repeated_times, rich_tracebacks=rich_tracebacks, show_level=show_level, show_path=show_path, show_time=show_time, tracebacks_code_width=tracebacks_code_width, tracebacks_extra_lines=tracebacks_extra_lines, tracebacks_max_frames=tracebacks_max_frames, tracebacks_show_locals=tracebacks_show_locals, tracebacks_suppress=tracebacks_suppress, tracebacks_theme=tracebacks_theme, tracebacks_width=tracebacks_width, tracebacks_word_wrap=tracebacks_word_wrap, **kwargs, ) if log_render_kls is not None: self._log_render = log_render_kls( omit_repeated_times=omit_repeated_times, show_level=show_level, show_path=show_path, show_time=show_time, ) self._name = name
def _determine_should_escape(self, record: logging.LogRecord) -> bool: """Determine if a log message should be passed to :function:`~rich.markup.escape`. This can be overridden in subclasses for more control. """ return self._determine_use_markup(record) and getattr(record, "escape", False) def _determine_use_markup(self, record: logging.LogRecord) -> bool: """Determine if markup should be used for a log record.""" return getattr(record, "markup", self.markup)
[docs] def render_message(self, record: logging.LogRecord, message: str) -> ConsoleRenderable: """Render message text in to Text. Args: record: logging Record. message: String containing log message. Returns: ConsoleRenderable: Renderable to display log message. """ if self._determine_should_escape(record): message = escape(message) return super().render_message(*self._style_message(record, message))
def _style_message( self, record: logging.LogRecord, message: str, ) -> tuple[logging.LogRecord, str]: """Apply style to the message.""" if not self._determine_use_markup(record): return record, message return record, Text.from_markup(message, style=record.levelname.lower()).markup
[docs] def get_level_text(self, record: logging.LogRecord) -> Text: """Get the level name from the record. Args: record: LogRecord instance. Returns: Text: A tuple of the style and level name. """ level_name = record.levelname return Text.styled(f"[{level_name}]".ljust(9), f"logging.level.{level_name.lower()}")