Как окрасить вывод логирования 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 с отладочной информацией?
Конфигурация логгера для записи в файл и вывода на stdout
Настройка логирования в Python: вывод всех сообщений в stdout и файл журнала
Как заставить логгер удалять существующий файл журнала перед записью в него?
Как использовать UTF-8 в логировании Python?