Source code for app.util.logging.rich_handler

# SPDX-License-Identifier: GPLv3-or-later
# Copyright © 2025 pygaindalf Rui Pinheiro


from pathlib import Path
from typing import TYPE_CHECKING, override

from rich.console import Console, ConsoleRenderable, RenderableType
from rich.containers import Renderables
from rich.logging import RichHandler
from rich.table import Table
from rich.text import Text


if TYPE_CHECKING:
    import logging

    from rich.traceback import Traceback


[docs] class CustomRichHandler(RichHandler):
[docs] @override def __init__( self, *args, rich_tracebacks: bool = True, show_path: bool = True, show_level: bool = True, level_width: int = 1, level_color_everything: bool = True, level_prefix: str = "[", level_suffix: str = "] ", show_name: bool = True, enable_link_path: bool = False, **kwargs, ) -> None: console = Console(stderr=True) super().__init__(*args, console=console, rich_tracebacks=rich_tracebacks, enable_link_path=enable_link_path, **kwargs) self.show_path = show_path self.show_level = show_level self.level_width = level_width self.level_color_everything = level_color_everything self.show_name = show_name self.level_prefix = level_prefix self.level_suffix = level_suffix
[docs] def should_format(self, record: logging.LogRecord) -> bool: simple = getattr(record, "simple", False) return not simple
[docs] def get_level(self, record: logging.LogRecord) -> str: name = record.levelname return name[0].ljust(self.level_width)
[docs] def get_level_style(self, record: logging.LogRecord) -> str: return f"logging.level.{record.levelname.lower()}"
[docs] def get_message_style(self, record: logging.LogRecord) -> str: if self.level_color_everything: return self.get_level_style(record) else: return "log.message"
[docs] @override def render_message(self, record: logging.LogRecord, message: str) -> ConsoleRenderable: """Render message text in to Text. Args: record (LogRecord): logging Record. message (str): String containing log message. Returns: ConsoleRenderable: Renderable to display log message. """ text = Text() if self.should_format(record): if self.show_level or self.show_name: text.append(self.level_prefix, style="dim") if self.show_level: text.append(self.get_level(record), style=self.get_level_style(record)) if self.show_name: text.append(f"{':' if self.show_level else ''}{record.name}", style="dim") if self.show_level or self.show_name: text.append(self.level_suffix, style="dim") text.append(message) return text
[docs] @override def render(self, *args, record: logging.LogRecord, message_renderable: ConsoleRenderable, traceback: Traceback | None, **kwargs) -> ConsoleRenderable: if not self.should_format(record): return message_renderable path = Path(record.pathname).name line_no = record.lineno link_path = record.pathname if self.enable_link_path else None renderables = [message_renderable] if traceback: renderables.append(traceback) # Setup table output = Table.grid(padding=(0, 1)) output.expand = True output.add_column(ratio=1, style=self.get_message_style(record), overflow="fold") if self.show_path and path: output.add_column(style="log.path") # Setup row contents row: list[RenderableType] = [] row.append(Renderables(renderables)) if self.show_path and path: path_text = Text() path_text.append(path, style=f"link file://{link_path}" if link_path else "") if line_no: path_text.append(":") path_text.append( f"{line_no}", style=f"link file://{link_path}#{line_no}" if link_path else "", ) row.append(path_text) output.add_row(*row) # Done return output