Team Ai
Datasetpublic

codekingpro/portable-devtools

sourceHugging Faceupdated 5mo agoView on Hugging Face
1likes14kdownloads
logging.py290 linesDownload Raw Back to rich
1import logging2from datetime import datetime3from logging import Handler, LogRecord4from pathlib import Path5from types import ModuleType6from typing import ClassVar, Iterable, List, Optional, Type, Union7 8from rich._null_file import NullFile9 10from . import get_console11from ._log_render import FormatTimeCallable, LogRender12from .console import Console, ConsoleRenderable13from .highlighter import Highlighter, ReprHighlighter14from .text import Text15from .traceback import Traceback16 17 18class RichHandler(Handler):19    """A logging handler that renders output with Rich. The time / level / message and file are displayed in columns.20    The level is color coded, and the message is syntax highlighted.21 22    Note:23        Be careful when enabling console markup in log messages if you have configured logging for libraries not24        under your control. If a dependency writes messages containing square brackets, it may not produce the intended output.25 26    Args:27        level (Union[int, str], optional): Log level. Defaults to logging.NOTSET.28        console (:class:`~rich.console.Console`, optional): Optional console instance to write logs.29            Default will use a global console instance writing to stdout.30        show_time (bool, optional): Show a column for the time. Defaults to True.31        omit_repeated_times (bool, optional): Omit repetition of the same time. Defaults to True.32        show_level (bool, optional): Show a column for the level. Defaults to True.33        show_path (bool, optional): Show the path to the original log call. Defaults to True.34        enable_link_path (bool, optional): Enable terminal link of path column to file. Defaults to True.35        highlighter (Highlighter, optional): Highlighter to style log messages, or None to use ReprHighlighter. Defaults to None.36        markup (bool, optional): Enable console markup in log messages. Defaults to False.37        rich_tracebacks (bool, optional): Enable rich tracebacks with syntax highlighting and formatting. Defaults to False.38        tracebacks_width (Optional[int], optional): Number of characters used to render tracebacks, or None for full width. Defaults to None.39        tracebacks_extra_lines (int, optional): Additional lines of code to render tracebacks, or None for full width. Defaults to None.40        tracebacks_theme (str, optional): Override pygments theme used in traceback.41        tracebacks_word_wrap (bool, optional): Enable word wrapping of long tracebacks lines. Defaults to True.42        tracebacks_show_locals (bool, optional): Enable display of locals in tracebacks. Defaults to False.43        tracebacks_suppress (Sequence[Union[str, ModuleType]]): Optional sequence of modules or paths to exclude from traceback.44        locals_max_length (int, optional): Maximum length of containers before abbreviating, or None for no abbreviation.45            Defaults to 10.46        locals_max_string (int, optional): Maximum length of string before truncating, or None to disable. Defaults to 80.47        log_time_format (Union[str, TimeFormatterCallable], optional): If ``log_time`` is enabled, either string for strftime or callable that formats the time. Defaults to "[%x %X] ".48        keywords (List[str], optional): List of words to highlight instead of ``RichHandler.KEYWORDS``.49    """50 51    KEYWORDS: ClassVar[Optional[List[str]]] = [52        "GET",53        "POST",54        "HEAD",55        "PUT",56        "DELETE",57        "OPTIONS",58        "TRACE",59        "PATCH",60    ]61    HIGHLIGHTER_CLASS: ClassVar[Type[Highlighter]] = ReprHighlighter62 63    def __init__(64        self,65        level: Union[int, str] = logging.NOTSET,66        console: Optional[Console] = None,67        *,68        show_time: bool = True,69        omit_repeated_times: bool = True,70        show_level: bool = True,71        show_path: bool = True,72        enable_link_path: bool = True,73        highlighter: Optional[Highlighter] = None,74        markup: bool = False,75        rich_tracebacks: bool = False,76        tracebacks_width: Optional[int] = None,77        tracebacks_extra_lines: int = 3,78        tracebacks_theme: Optional[str] = None,79        tracebacks_word_wrap: bool = True,80        tracebacks_show_locals: bool = False,81        tracebacks_suppress: Iterable[Union[str, ModuleType]] = (),82        locals_max_length: int = 10,83        locals_max_string: int = 80,84        log_time_format: Union[str, FormatTimeCallable] = "[%x %X]",85        keywords: Optional[List[str]] = None,86    ) -> None:87        super().__init__(level=level)88        self.console = console or get_console()89        self.highlighter = highlighter or self.HIGHLIGHTER_CLASS()90        self._log_render = LogRender(91            show_time=show_time,92            show_level=show_level,93            show_path=show_path,94            time_format=log_time_format,95            omit_repeated_times=omit_repeated_times,96            level_width=None,97        )98        self.enable_link_path = enable_link_path99        self.markup = markup100        self.rich_tracebacks = rich_tracebacks101        self.tracebacks_width = tracebacks_width102        self.tracebacks_extra_lines = tracebacks_extra_lines103        self.tracebacks_theme = tracebacks_theme104        self.tracebacks_word_wrap = tracebacks_word_wrap105        self.tracebacks_show_locals = tracebacks_show_locals106        self.tracebacks_suppress = tracebacks_suppress107        self.locals_max_length = locals_max_length108        self.locals_max_string = locals_max_string109        self.keywords = keywords110 111    def get_level_text(self, record: LogRecord) -> Text:112        """Get the level name from the record.113 114        Args:115            record (LogRecord): LogRecord instance.116 117        Returns:118            Text: A tuple of the style and level name.119        """120        level_name = record.levelname121        level_text = Text.styled(122            level_name.ljust(8), f"logging.level.{level_name.lower()}"123        )124        return level_text125 126    def emit(self, record: LogRecord) -> None:127        """Invoked by logging."""128        message = self.format(record)129        traceback = None130        if (131            self.rich_tracebacks132            and record.exc_info133            and record.exc_info != (None, None, None)134        ):135            exc_type, exc_value, exc_traceback = record.exc_info136            assert exc_type is not None137            assert exc_value is not None138            traceback = Traceback.from_exception(139                exc_type,140                exc_value,141                exc_traceback,142                width=self.tracebacks_width,143                extra_lines=self.tracebacks_extra_lines,144                theme=self.tracebacks_theme,145                word_wrap=self.tracebacks_word_wrap,146                show_locals=self.tracebacks_show_locals,147                locals_max_length=self.locals_max_length,148                locals_max_string=self.locals_max_string,149                suppress=self.tracebacks_suppress,150            )151            message = record.getMessage()152            if self.formatter:153                record.message = record.getMessage()154                formatter = self.formatter155                if hasattr(formatter, "usesTime") and formatter.usesTime():156                    record.asctime = formatter.formatTime(record, formatter.datefmt)157                message = formatter.formatMessage(record)158 159        message_renderable = self.render_message(record, message)160        log_renderable = self.render(161            record=record, traceback=traceback, message_renderable=message_renderable162        )163        if isinstance(self.console.file, NullFile):164            # Handles pythonw, where stdout/stderr are null, and we return NullFile165            # instance from Console.file. In this case, we still want to make a log record166            # even though we won't be writing anything to a file.167            self.handleError(record)168        else:169            try:170                self.console.print(log_renderable)171            except Exception:172                self.handleError(record)173 174    def render_message(self, record: LogRecord, message: str) -> "ConsoleRenderable":175        """Render message text in to Text.176 177        Args:178            record (LogRecord): logging Record.179            message (str): String containing log message.180 181        Returns:182            ConsoleRenderable: Renderable to display log message.183        """184        use_markup = getattr(record, "markup", self.markup)185        message_text = Text.from_markup(message) if use_markup else Text(message)186 187        highlighter = getattr(record, "highlighter", self.highlighter)188        if highlighter:189            message_text = highlighter(message_text)190 191        if self.keywords is None:192            self.keywords = self.KEYWORDS193 194        if self.keywords:195            message_text.highlight_words(self.keywords, "logging.keyword")196 197        return message_text198 199    def render(200        self,201        *,202        record: LogRecord,203        traceback: Optional[Traceback],204        message_renderable: "ConsoleRenderable",205    ) -> "ConsoleRenderable":206        """Render log for display.207 208        Args:209            record (LogRecord): logging Record.210            traceback (Optional[Traceback]): Traceback instance or None for no Traceback.211            message_renderable (ConsoleRenderable): Renderable (typically Text) containing log message contents.212 213        Returns:214            ConsoleRenderable: Renderable to display log.215        """216        path = Path(record.pathname).name217        level = self.get_level_text(record)218        time_format = None if self.formatter is None else self.formatter.datefmt219        log_time = datetime.fromtimestamp(record.created)220 221        log_renderable = self._log_render(222            self.console,223            [message_renderable] if not traceback else [message_renderable, traceback],224            log_time=log_time,225            time_format=time_format,226            level=level,227            path=path,228            line_no=record.lineno,229            link_path=record.pathname if self.enable_link_path else None,230        )231        return log_renderable232 233 234if __name__ == "__main__":  # pragma: no cover235    from time import sleep236 237    FORMAT = "%(message)s"238    # FORMAT = "%(asctime)-15s - %(levelname)s - %(message)s"239    logging.basicConfig(240        level="NOTSET",241        format=FORMAT,242        datefmt="[%X]",243        handlers=[RichHandler(rich_tracebacks=True, tracebacks_show_locals=True)],244    )245    log = logging.getLogger("rich")246 247    log.info("Server starting...")248    log.info("Listening on http://127.0.0.1:8080")249    sleep(1)250 251    log.info("GET /index.html 200 1298")252    log.info("GET /imgs/backgrounds/back1.jpg 200 54386")253    log.info("GET /css/styles.css 200 54386")254    log.warning("GET /favicon.ico 404 242")255    sleep(1)256 257    log.debug(258        "JSONRPC request\n--> %r\n<-- %r",259        {260            "version": "1.1",261            "method": "confirmFruitPurchase",262            "params": [["apple", "orange", "mangoes", "pomelo"], 1.123],263            "id": "194521489",264        },265        {"version": "1.1", "result": True, "error": None, "id": "194521489"},266    )267    log.debug(268        "Loading configuration file /adasd/asdasd/qeqwe/qwrqwrqwr/sdgsdgsdg/werwerwer/dfgerert/ertertert/ertetert/werwerwer"269    )270    log.error("Unable to find 'pomelo' in database!")271    log.info("POST /jsonrpc/ 200 65532")272    log.info("POST /admin/ 401 42234")273    log.warning("password was rejected for admin site.")274 275    def divide() -> None:276        number = 1277        divisor = 0278        foos = ["foo"] * 100279        log.debug("in divide")280        try:281            number / divisor282        except:283            log.exception("An error of some kind occurred!")284 285    divide()286    sleep(1)287    log.critical("Out of memory!")288    log.info("Server exited with code=-1")289    log.info("[bold]EXITING...[/bold]", extra=dict(markup=True))290 
codekingpro/portable-devtools · Team Ai