handle exceptions with rich's logging handler

This commit is contained in:
landi 2020-09-23 00:49:49 +02:00
parent 4e24f2ef1a
commit 0fac8d5eab
3 changed files with 95 additions and 11 deletions

View file

@ -20,4 +20,17 @@ Rich logs won't render :ref:`console_markup` in logging by default as most libra
log.error("[bold red blink]Server is shutting down![/]", extra={"markup": True})
Handle exceptions
-------------------
Rich's :class:`~rich.logging.RichHandler` class can be configured to handle exceptions. Here's an example::
handler = RichHandler(handle_tracebacks=True)
try:
1 / 0
except ZeroDivisionError:
log.exception("Exception message")
There are a number of options you can use to configure logging output, see the :class:`~rich.logging.RichHandler` reference for details.

View file

@ -29,6 +29,11 @@ class RichHandler(Handler):
enable_link_path (bool, optional): Enable terminal link of path column to file. Defaults to True.
highlighter (Highlighter, optional): Highlighter to style log messages, or None to use ReprHighlighter. Defaults to None.
markup (bool, optional): Enable console markup in log messages. Defaults to False.
handle_tracebacks (bool, optional): Enable rich tracebacks with syntax highlighting and formatting. Defaults to False.
tracebacks_width (Optional[int], optional): Number of characters used to render tracebacks code. Defaults to 88.
tracebacks_extra_lines (int, optional): Additional lines of code to render tracebacks. Defaults to 3.
tracebacks_theme (str, optional): Override pygments theme used in traceback
tracebacks_word_wrap (bool, optional): Enable word wrapping of long tracebacks lines. Defaults to False.
"""
@ -55,6 +60,11 @@ class RichHandler(Handler):
enable_link_path: bool = True,
highlighter: Highlighter = None,
markup: bool = False,
handle_tracebacks: bool = False,
tracebacks_width: Optional[int] = 88,
tracebacks_extra_lines: int = 3,
tracebacks_theme: Optional[str] = None,
tracebacks_word_wrap: bool = False,
) -> None:
super().__init__(level=level)
self.console = console or get_console()
@ -64,6 +74,11 @@ class RichHandler(Handler):
)
self.enable_link_path = enable_link_path
self.markup = markup
self.handle_tracebacks = handle_tracebacks
self.tracebacks_width = tracebacks_width
self.tracebacks_extra_lines = tracebacks_extra_lines
self.tracebacks_theme = tracebacks_theme
self.tracebacks_word_wrap = tracebacks_word_wrap
def emit(self, record: LogRecord) -> None:
"""Invoked by logging."""
@ -89,18 +104,26 @@ class RichHandler(Handler):
if self.KEYWORDS:
message_text.highlight_words(self.KEYWORDS, "logging.keyword")
self.console.print(
self._log_render(
self.console,
[message_text],
log_time=log_time,
time_format=time_format,
level=level,
path=path,
line_no=record.lineno,
link_path=record.pathname if self.enable_link_path else None,
if self.handle_tracebacks and record.exc_info:
self.console.print_exception(
width=self.tracebacks_width,
extra_lines=self.tracebacks_extra_lines,
theme=self.tracebacks_theme,
word_wrap=self.tracebacks_word_wrap,
)
else:
self.console.print(
self._log_render(
self.console,
[message_text],
log_time=log_time,
time_format=time_format,
level=level,
path=path,
line_no=record.lineno,
link_path=record.pathname if self.enable_link_path else None,
)
)
)
if __name__ == "__main__": # pragma: no cover

View file

@ -29,6 +29,54 @@ def test_log():
assert render == expected
def test_exception():
console = Console(
file=io.StringIO(), force_terminal=True, width=80, color_system="truecolor"
)
handler_with_tracebacks = RichHandler(
console=console, enable_link_path=False, handle_tracebacks=True
)
log.addHandler(handler_with_tracebacks)
try:
1 / 0
except ZeroDivisionError:
log.exception("message")
render = handler_with_tracebacks.console.file.getvalue()
print(render)
excpected = "ZeroDivisionError: \x1b[0mdivision by zero\n"
assert excpected == render[-40:]
assert render.count("\n") == 13
def test_exception_with_extra_lines():
console = Console(
file=io.StringIO(), force_terminal=True, width=80, color_system="truecolor"
)
handler_extra_lines = RichHandler(
console=console,
enable_link_path=False,
markup=True,
handle_tracebacks=True,
tracebacks_extra_lines=5,
)
log.addHandler(handler_extra_lines)
try:
1 / 0
except ZeroDivisionError:
log.exception("message")
render = handler_extra_lines.console.file.getvalue()
print(render)
excpected = "ZeroDivisionError: \x1b[0mdivision by zero\n"
assert excpected == render[-40:]
assert render.count("\n") == 17
if __name__ == "__main__":
render = make_log()
print(render)