logging: Make it possible to add cli colors to custom log levels
Closes #8803 PR #8804 Co-authored-by: Bruno Oliveira <nicoddemus@gmail.com> Co-authored-by: Terje Runde <terje.runde@flir.com> Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
This commit is contained in:
parent
df033f3ab1
commit
2439729413
1
AUTHORS
1
AUTHORS
|
@ -309,6 +309,7 @@ Tanvi Mehta
|
||||||
Tarcisio Fischer
|
Tarcisio Fischer
|
||||||
Tareq Alayan
|
Tareq Alayan
|
||||||
Ted Xiao
|
Ted Xiao
|
||||||
|
Terje Runde
|
||||||
Thomas Grainger
|
Thomas Grainger
|
||||||
Thomas Hisch
|
Thomas Hisch
|
||||||
Tim Hoffmann
|
Tim Hoffmann
|
||||||
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
It is now possible to add colors to custom log levels on cli log.
|
||||||
|
|
||||||
|
By using :func:`add_color_level <_pytest.logging.add_color_level` from a ``pytest_configure`` hook, colors can be added::
|
||||||
|
|
||||||
|
logging_plugin = config.pluginmanager.get_plugin('logging-plugin')
|
||||||
|
logging_plugin.log_cli_handler.formatter.add_color_level(logging.INFO, 'cyan')
|
||||||
|
logging_plugin.log_cli_handler.formatter.add_color_level(logging.SPAM, 'blue')
|
||||||
|
|
||||||
|
See :ref:`log_colors` for more information.
|
|
@ -219,6 +219,30 @@ option names are:
|
||||||
You can call ``set_log_path()`` to customize the log_file path dynamically. This functionality
|
You can call ``set_log_path()`` to customize the log_file path dynamically. This functionality
|
||||||
is considered **experimental**.
|
is considered **experimental**.
|
||||||
|
|
||||||
|
.. _log_colors:
|
||||||
|
|
||||||
|
Customizing Colors
|
||||||
|
^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
Log levels are colored if colored terminal output is enabled. Changing
|
||||||
|
from default colors or putting color on custom log levels is supported
|
||||||
|
through ``add_color_level()``. Example:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
@pytest.hookimpl
|
||||||
|
def pytest_configure(config):
|
||||||
|
logging_plugin = config.pluginmanager.get_plugin("logging-plugin")
|
||||||
|
|
||||||
|
# Change color on existing log level
|
||||||
|
logging_plugin.log_cli_handler.formatter.add_color_level(logging.INFO, "cyan")
|
||||||
|
|
||||||
|
# Add color to a custom log level (a custom log level `SPAM` is already set up)
|
||||||
|
logging_plugin.log_cli_handler.formatter.add_color_level(logging.SPAM, "blue")
|
||||||
|
.. warning::
|
||||||
|
|
||||||
|
This feature and its API are considered **experimental** and might change
|
||||||
|
between releases without a deprecation notice.
|
||||||
.. _log_release_notes:
|
.. _log_release_notes:
|
||||||
|
|
||||||
Release notes
|
Release notes
|
||||||
|
|
|
@ -63,28 +63,43 @@ class ColoredLevelFormatter(logging.Formatter):
|
||||||
|
|
||||||
def __init__(self, terminalwriter: TerminalWriter, *args, **kwargs) -> None:
|
def __init__(self, terminalwriter: TerminalWriter, *args, **kwargs) -> None:
|
||||||
super().__init__(*args, **kwargs)
|
super().__init__(*args, **kwargs)
|
||||||
|
self._terminalwriter = terminalwriter
|
||||||
self._original_fmt = self._style._fmt
|
self._original_fmt = self._style._fmt
|
||||||
self._level_to_fmt_mapping: Dict[int, str] = {}
|
self._level_to_fmt_mapping: Dict[int, str] = {}
|
||||||
|
|
||||||
|
for level, color_opts in self.LOGLEVEL_COLOROPTS.items():
|
||||||
|
self.add_color_level(level, *color_opts)
|
||||||
|
|
||||||
|
def add_color_level(self, level: int, *color_opts: str) -> None:
|
||||||
|
"""Add or update color opts for a log level.
|
||||||
|
|
||||||
|
:param level:
|
||||||
|
Log level to apply a style to, e.g. ``logging.INFO``.
|
||||||
|
:param color_opts:
|
||||||
|
ANSI escape sequence color options. Capitalized colors indicates
|
||||||
|
background color, i.e. ``'green', 'Yellow', 'bold'`` will give bold
|
||||||
|
green text on yellow background.
|
||||||
|
|
||||||
|
.. warning::
|
||||||
|
This is an experimental API.
|
||||||
|
"""
|
||||||
|
|
||||||
assert self._fmt is not None
|
assert self._fmt is not None
|
||||||
levelname_fmt_match = self.LEVELNAME_FMT_REGEX.search(self._fmt)
|
levelname_fmt_match = self.LEVELNAME_FMT_REGEX.search(self._fmt)
|
||||||
if not levelname_fmt_match:
|
if not levelname_fmt_match:
|
||||||
return
|
return
|
||||||
levelname_fmt = levelname_fmt_match.group()
|
levelname_fmt = levelname_fmt_match.group()
|
||||||
|
|
||||||
for level, color_opts in self.LOGLEVEL_COLOROPTS.items():
|
formatted_levelname = levelname_fmt % {"levelname": logging.getLevelName(level)}
|
||||||
formatted_levelname = levelname_fmt % {
|
|
||||||
"levelname": logging.getLevelName(level)
|
|
||||||
}
|
|
||||||
|
|
||||||
# add ANSI escape sequences around the formatted levelname
|
# add ANSI escape sequences around the formatted levelname
|
||||||
color_kwargs = {name: True for name in color_opts}
|
color_kwargs = {name: True for name in color_opts}
|
||||||
colorized_formatted_levelname = terminalwriter.markup(
|
colorized_formatted_levelname = self._terminalwriter.markup(
|
||||||
formatted_levelname, **color_kwargs
|
formatted_levelname, **color_kwargs
|
||||||
)
|
)
|
||||||
self._level_to_fmt_mapping[level] = self.LEVELNAME_FMT_REGEX.sub(
|
self._level_to_fmt_mapping[level] = self.LEVELNAME_FMT_REGEX.sub(
|
||||||
colorized_formatted_levelname, self._fmt
|
colorized_formatted_levelname, self._fmt
|
||||||
)
|
)
|
||||||
|
|
||||||
def format(self, record: logging.LogRecord) -> str:
|
def format(self, record: logging.LogRecord) -> str:
|
||||||
fmt = self._level_to_fmt_mapping.get(record.levelno, self._original_fmt)
|
fmt = self._level_to_fmt_mapping.get(record.levelno, self._original_fmt)
|
||||||
|
|
Loading…
Reference in New Issue