Как окрасить вывод логирования Python?
Заголовок: Как вывести цветной лог в Python с помощью модуля logging?
Некоторое время назад я наткнулся на приложение на Mono, которое имело цветной вывод, предположительно благодаря своей системе логирования (все сообщения были стандартизированы).
Теперь в Python есть модуль logging
, который позволяет настраивать множество параметров для вывода. Я предполагаю, что нечто подобное можно реализовать и в Python, но не могу найти информации о том, как это сделать.
Существует ли способ настроить вывод модуля logging
в цвете?
Я хочу, например, чтобы ошибки отображались красным, сообщения отладки — синим или желтым и так далее.
Конечно, это, вероятно, потребует совместимого терминала (но большинство современных терминалов поддерживают это); в противном случае я мог бы вернуться к оригинальному выводу logging
, если цвет не поддерживается.
Есть ли идеи, как получить цветной вывод с помощью модуля logging?
5 ответ(ов)
Чтобы быстро изменить стилизацию логов для предопределённых уровней логирования без создания нового класса, вы можете использовать функцию addLevelName
из модуля logging
. Это позволяет изменить отображаемые названия уровней и, например, добавить ANSI-коды для цветового оформления.
Вот пример, который задаёт красный текст для уровня WARNING
и красный фон для уровня ERROR
:
import logging
logging.addLevelName(logging.WARNING, "\033[1;31m%s\033[1;0m" % logging.getLevelName(logging.WARNING))
logging.addLevelName(logging.ERROR, "\033[1;41m%s\033[1;0m" % logging.getLevelName(logging.ERROR))
После выполнения этого кода, при выводе логов уровня WARNING
текст будет красным, а для ERROR
фон будет красным.
Это быстрейший и грязный способ добиться желаемого эффекта без создания новых классов. Обратите внимание, что ANSI-коды могут не работать в некоторых средах, таких как Windows консоль, без дополнительной настройки.
Вот решение, которое должно работать на любой платформе. Если оно не сработает, просто дайте знать, и я обновлю его.
Как это работает: На платформах, поддерживающих ANSI-экраны, используются соответствующие команды (не Windows), а на Windows применяются API вызовы для изменения цветов консоли.
Скрипт перехватывает метод emit
класса logging.StreamHandler
из стандартной библиотеки, добавляя к нему оболочку.
TestColorer.py
# Использование: добавьте Colorer.py рядом с вашим скриптом и импортируйте его.
import logging
import Colorer
logging.warn("предупреждение")
logging.error("произошла ошибка")
logging.info("некоторая информация")
Colorer.py
#!/usr/bin/env python
# кодировка: utf-8
import logging
# Теперь мы добавляем поддержку цвета для logging.StreamHandler
def add_coloring_to_emit_windows(fn):
def _out_handle(self):
import ctypes
return ctypes.windll.kernel32.GetStdHandle(self.STD_OUTPUT_HANDLE)
out_handle = property(_out_handle)
def _set_color(self, code):
import ctypes
self.STD_OUTPUT_HANDLE = -11
hdl = ctypes.windll.kernel32.GetStdHandle(self.STD_OUTPUT_HANDLE)
ctypes.windll.kernel32.SetConsoleTextAttribute(hdl, code)
setattr(logging.StreamHandler, '_set_color', _set_color)
def new(*args):
FOREGROUND_BLUE = 0x0001
FOREGROUND_GREEN = 0x0002
FOREGROUND_RED = 0x0004
FOREGROUND_INTENSITY = 0x0008
FOREGROUND_WHITE = FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED
levelno = args[1].levelno
if levelno >= 50:
color = FOREGROUND_RED | FOREGROUND_INTENSITY
elif levelno >= 40:
color = FOREGROUND_RED | FOREGROUND_INTENSITY
elif levelno >= 30:
color = FOREGROUND_YELLOW | FOREGROUND_INTENSITY
elif levelno >= 20:
color = FOREGROUND_GREEN
elif levelno >= 10:
color = FOREGROUND_MAGENTA
else:
color = FOREGROUND_WHITE
args[0]._set_color(color)
ret = fn(*args)
args[0]._set_color(FOREGROUND_WHITE)
return ret
return new
def add_coloring_to_emit_ansi(fn):
def new(*args):
levelno = args[1].levelno
if levelno >= 50:
color = '\x1b[31m' # красный
elif levelno >= 40:
color = '\x1b[31m' # красный
elif levelno >= 30:
color = '\x1b[33m' # желтый
elif levelno >= 20:
color = '\x1b[32m' # зеленый
elif levelno >= 10:
color = '\x1b[35m' # розовый
else:
color = '\x1b[0m' # нормальный
args[1].msg = color + args[1].msg + '\x1b[0m' # нормальный
return fn(*args)
return new
import platform
if platform.system() == 'Windows':
logging.StreamHandler.emit = add_coloring_to_emit_windows(logging.StreamHandler.emit)
else:
logging.StreamHandler.emit = add_coloring_to_emit_ansi(logging.StreamHandler.emit)
Если у вас возникнут вопросы или проблемы с этим кодом, не стесняйтесь задавать их!
Вы обновили пример кода для airmind, добавив поддержку тегов для переднего и заднего фонов. Чтобы использовать цвета, вы можете воспользоваться переменными цвета $BLACK
- $WHITE
в строке форматирования вашего логгера. Для установки фона используйте $BG-BLACK
- $BG-WHITE
.
Вот как это выглядит на практике:
import logging
BLACK, RED, GREEN, YELLOW, BLUE, MAGENTA, CYAN, WHITE = range(8)
COLORS = {
'WARNING' : YELLOW,
'INFO' : WHITE,
'DEBUG' : BLUE,
'CRITICAL' : YELLOW,
'ERROR' : RED,
'RED' : RED,
'GREEN' : GREEN,
'YELLOW' : YELLOW,
'BLUE' : BLUE,
'MAGENTA' : MAGENTA,
'CYAN' : CYAN,
'WHITE' : WHITE,
}
RESET_SEQ = "\033[0m"
COLOR_SEQ = "\033[1;%dm"
BOLD_SEQ = "\033[1m"
class ColorFormatter(logging.Formatter):
def __init__(self, *args, **kwargs):
# нельзя использовать super(...) здесь, так как Formatter - это старая школа
logging.Formatter.__init__(self, *args, **kwargs)
def format(self, record):
levelname = record.levelname
color = COLOR_SEQ % (30 + COLORS[levelname])
message = logging.Formatter.format(self, record)
message = message.replace("$RESET", RESET_SEQ)\
.replace("$BOLD", BOLD_SEQ)\
.replace("$COLOR", color)
for k,v in COLORS.items():
message = message.replace("$" + k, COLOR_SEQ % (v+30))\
.replace("$BG" + k, COLOR_SEQ % (v+40))\
.replace("$BG-" + k, COLOR_SEQ % (v+40))
return message + RESET_SEQ
logging.ColorFormatter = ColorFormatter
Теперь вы можете просто сделать следующее в вашем конфигурационном файле:
[formatter_colorFormatter]
class=logging.ColorFormatter
format= $COLOR%(levelname)s $RESET %(asctime)s $BOLD$COLOR%(name)s$RESET %(message)s
Таким образом, вы сможете легко менять цвета логов, используя переменные.
Рассмотрим следующее решение. Обработчик потока должен заниматься окрашиванием, тогда у вас будет возможность окрашивать слова, а не только целые строки (с помощью Formatter).
Вы можете ознакомиться с более подробной информацией по этой теме в блоге Plumberjack.
Сейчас доступен модуль PyPi для настраиваемого цветного логирования:
Этот модуль:
- Поддерживает Windows
- Поддерживает Django
- Позволяет настраивать цвета
Поскольку он распространяется в виде Python egg, установить его просто для любого Python-приложения.
Сохранение сообщений об исключениях в Python
Как зарегистрировать ошибку в Python с отладочной информацией?
Конфигурация логгера для записи в файл и вывода на stdout
Настройка логирования в Python: вывод всех сообщений в stdout и файл журнала
Как клонировать список, чтобы он не изменялся неожиданно после присваивания?