Некоторое время назад я видел приложение Mono с цветным выводом, предположительно из-за его системы журналов (поскольку все сообщения были стандартизированы).
Теперь в Python есть модуль logging, который позволяет указать множество параметров для настройки вывода. Итак, я представляю себе нечто подобное с Python, но я нигде не могу найти, как это сделать.
Есть ли способ сделать вывод модуля Python logging в цвете?
То, что мне нужно (например), ошибки - красным, отладочные сообщения - синим или желтым и так далее.
Конечно, для этого, вероятно, потребуется совместимый терминал (в большинстве современных терминалов); но я мог бы вернуться к исходному выводу logging, если цвет не поддерживается.
Есть идеи, как я могу получить цветной вывод с помощью модуля регистрации?
Связано, если вы используете Eclipse / PyDev: Раскрашиваем журналы в консоли eclipse
Возможно, вы также можете использовать colorlog
запустите pip install ipython и добавьте alias python = "ipython" в сценарий запуска оболочки (например, ~/.bashrc для оболочки bash)
Вы также можете попробовать хромалог, который я написал для поддержки всех операционных систем и версий Python (2.7 и 3. *)
Решения, которые на самом деле сбрасывают коды ANSI в файл журнала, являются плохой идеей, они поймают вас, когда вы будете искать что-то через шесть месяцев, но забудете разрешить символы ANSI в своем шаблоне регулярного выражения. Ниже приведены некоторые решения, которые добавляют цвет при просмотре журнала, а не во время его записи ...
FriendlyLog (github.com/SebiSebi/friendlylog) - еще одна альтернатива. Он работает с Python 2 и 3 под Linux, Windows и MacOS.
@JonathanHartley Это причина, по которой вы устанавливаете несколько обработчиков журналов. Вы можете настроить StreamHandler ведения журнала для отправки вывода журнала в потоки, такие как sys.stdout и / или sys.stderr Обработчики, отправляющие в stdout / stderr, можно раскрасить, этот вывод существует только в окне терминала. Затем вы настраиваете другой обработчик журнала, который отправляет выходные данные журнала в файл журнала (и не окрашивает сообщения).
для этого вам даже не нужны пакеты, посмотрите stackoverflow.com/a/56944256/9150146
если вы хотите включить цвет только тогда, когда stdout является терминалом: stackoverflow.com/questions/1077113/…






Я уже знал о цветовом экранировании, я использовал их в своей командной строке bash некоторое время назад. В любом случае спасибо. Я хотел интегрировать его с модулем ведения журнала, что в конечном итоге и сделал после пары попыток и ошибок. Вот что у меня получается:
BLACK, RED, GREEN, YELLOW, BLUE, MAGENTA, CYAN, WHITE = range(8)
#The background is set with 40 plus the number of the color, and the foreground with 30
#These are the sequences need to get colored ouput
RESET_SEQ = "\033[0m"
COLOR_SEQ = "\033[1;%dm"
BOLD_SEQ = "\033[1m"
def formatter_message(message, use_color = True):
if use_color:
message = message.replace("$RESET", RESET_SEQ).replace("$BOLD", BOLD_SEQ)
else:
message = message.replace("$RESET", "").replace("$BOLD", "")
return message
COLORS = {
'WARNING': YELLOW,
'INFO': WHITE,
'DEBUG': BLUE,
'CRITICAL': YELLOW,
'ERROR': RED
}
class ColoredFormatter(logging.Formatter):
def __init__(self, msg, use_color = True):
logging.Formatter.__init__(self, msg)
self.use_color = use_color
def format(self, record):
levelname = record.levelname
if self.use_color and levelname in COLORS:
levelname_color = COLOR_SEQ % (30 + COLORS[levelname]) + levelname + RESET_SEQ
record.levelname = levelname_color
return logging.Formatter.format(self, record)
И чтобы использовать его, создайте свой собственный Регистратор:
# Custom logger class with multiple destinations
class ColoredLogger(logging.Logger):
FORMAT = "[$BOLD%(name)-20s$RESET][%(levelname)-18s] %(message)s ($BOLD%(filename)s$RESET:%(lineno)d)"
COLOR_FORMAT = formatter_message(FORMAT, True)
def __init__(self, name):
logging.Logger.__init__(self, name, logging.DEBUG)
color_formatter = ColoredFormatter(self.COLOR_FORMAT)
console = logging.StreamHandler()
console.setFormatter(color_formatter)
self.addHandler(console)
return
logging.setLoggerClass(ColoredLogger)
На всякий случай это кому-нибудь еще понадобится.
Будьте осторожны, если вы используете более одного регистратора или обработчика: ColoredFormatter изменяет объект записи, который передается дальше другим обработчикам или распространяется на другие регистраторы. Если вы настроили регистраторы файлов и т. д., Вы, вероятно, не захотите иметь цвета в файлах журнала. Чтобы избежать этого, вероятно, лучше всего просто создать копию record с copy.copy() перед манипулированием атрибутом levelname или сбросить имя уровня до предыдущего значения, прежде чем возвращать отформатированную строку (указание на Майкл в комментариях).
Где определяется ЖЕЛТЫЙ, БЕЛЫЙ, СИНИЙ и т. д.?
@Swaroop - это escape-коды ANSI, которые вы можете прочитать в Google или найти здесь: en.wikipedia.org/wiki/ANSI_escape_code, или, альтернативно, pueblo.sourceforge.net/doc/manual/ansi_color_codes.html
Я не верю, что вам следует создавать подкласс регистратора только для этого - ваш ответ хорош, если вы создадите специализированный Formatter и укажете его использование на StreamHandler. Но нет необходимости в подклассе регистратора. Фактически, использование класса регистратора добавляет обработчик к каждому созданному регистратору, что обычно не является тем, что вам нужно.
@Vinay - не могли бы вы подробнее рассказать, как это реализовать?
@simon: plumberjack.blogspot.co.uk/2010/12/…
Одно примечание к ColoredFormatter. Он изменяет объект записи, который передается другим обработчикам или распространяется на другие регистраторы. Если вы настроили регистраторы файлов и т. д., Вы, вероятно, не захотите иметь цвета в файлах журнала. Чтобы избежать этого, вероятно, лучше всего просто создать копию record с copy.copy() перед манипулированием атрибутом levelname или сбросить имя уровня на предыдущее значение перед возвратом отформатированной строки.
Вот решение, которое должно работать на любой платформе. Если это не так, просто скажите мне, и я обновлю его.
Как это работает: на платформе, поддерживающей escape-последовательности ANSI, они используются (не в Windows), а в Windows используются вызовы API для изменения цвета консоли.
Скрипт взламывает метод logging.StreamHandler.emit из стандартной библиотеки, добавляя к нему оболочку.
TestColorer.py
# Usage: add Colorer.py near you script and import it.
import logging
import Colorer
logging.warn("a warning")
logging.error("some error")
logging.info("some info")
Colorer.py
#!/usr/bin/env python
# encoding: utf-8
import logging
# now we patch Python code to add color support to logging.StreamHandler
def add_coloring_to_emit_windows(fn):
# add methods we need to the class
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
# Constants from the Windows API
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 # text color contains blue.
FOREGROUND_GREEN = 0x0002 # text color contains green.
FOREGROUND_RED = 0x0004 # text color contains red.
FOREGROUND_INTENSITY = 0x0008 # text color is intensified.
FOREGROUND_WHITE = FOREGROUND_BLUE|FOREGROUND_GREEN |FOREGROUND_RED
# winbase.h
STD_INPUT_HANDLE = -10
STD_OUTPUT_HANDLE = -11
STD_ERROR_HANDLE = -12
# wincon.h
FOREGROUND_BLACK = 0x0000
FOREGROUND_BLUE = 0x0001
FOREGROUND_GREEN = 0x0002
FOREGROUND_CYAN = 0x0003
FOREGROUND_RED = 0x0004
FOREGROUND_MAGENTA = 0x0005
FOREGROUND_YELLOW = 0x0006
FOREGROUND_GREY = 0x0007
FOREGROUND_INTENSITY = 0x0008 # foreground color is intensified.
BACKGROUND_BLACK = 0x0000
BACKGROUND_BLUE = 0x0010
BACKGROUND_GREEN = 0x0020
BACKGROUND_CYAN = 0x0030
BACKGROUND_RED = 0x0040
BACKGROUND_MAGENTA = 0x0050
BACKGROUND_YELLOW = 0x0060
BACKGROUND_GREY = 0x0070
BACKGROUND_INTENSITY = 0x0080 # background color is intensified.
levelno = args[1].levelno
if (levelno>=50):
color = BACKGROUND_YELLOW | FOREGROUND_RED | FOREGROUND_INTENSITY | BACKGROUND_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 )
#print "after"
return ret
return new
def add_coloring_to_emit_ansi(fn):
# add methods we need to the class
def new(*args):
levelno = args[1].levelno
if (levelno>=50):
color = '\x1b[31m' # red
elif (levelno>=40):
color = '\x1b[31m' # red
elif (levelno>=30):
color = '\x1b[33m' # yellow
elif (levelno>=20):
color = '\x1b[32m' # green
elif (levelno>=10):
color = '\x1b[35m' # pink
else:
color = '\x1b[0m' # normal
args[1].msg = color + args[1].msg + '\x1b[0m' # normal
#print "after"
return fn(*args)
return new
import platform
if platform.system()=='Windows':
# Windows does not support ANSI escapes and we are using API calls to set the console color
logging.StreamHandler.emit = add_coloring_to_emit_windows(logging.StreamHandler.emit)
else:
# all non-Windows platforms are supporting ANSI escapes so we use them
logging.StreamHandler.emit = add_coloring_to_emit_ansi(logging.StreamHandler.emit)
#log = logging.getLogger()
#log.addFilter(log_filter())
#//hdlr = logging.StreamHandler()
#//hdlr.setFormatter(formatter())
На основе этого я написал класс StreamHandler, см. gist.github.com/mooware/a1ed40987b6cc9ab9c65.
это сработало для меня! строка 90: должно быть args[1].msg = color + str(args[1].msg) + '\x1b[0m' # normal.
Мне нравится это решение. использую его в настоящее время. Я вижу, что есть атрибут _set_color, есть ли способ сделать это для конкретного сообщения журнала? редактировать, видите ли, это просто патч для оконных машин. было бы неплохо добавить кастом для разных вариантов использования.
+1 для цвета ANSI. В xterm вы можете даже получить 256 цветов за раз, и вы можете динамически определять палитру! Обратите внимание, однако, что все вызовы функций регистрации должны быть внутри определения функции, чтобы избежать потенциального Проблемы с блокировкой импорта при входе в систему вне определения функции. Ваш код выглядит в основном хорошо; меня беспокоит только то, что есть в TestColorer.py.
Это приводит к цветовым кодам в начале и конце сообщений журнала в реальных файлах журнала.
Могу ли я оставить строку сообщения нормального цвета и раскрасить только секцию date, filename linenumber с левой стороны?
Я изменил исходный пример, предоставленный Сорином, и создал подкласс от StreamHandler до ColorizedConsoleHandler.
Обратной стороной их решения является то, что оно изменяет сообщение, и поскольку это изменяет фактическое сообщение журнала, любые другие обработчики также получат измененное сообщение.
В нашем случае это привело к появлению файлов журналов с цветовыми кодами, поскольку мы используем несколько регистраторов.
Приведенный ниже класс работает только на платформах, поддерживающих ansi, но добавление к нему цветовых кодов окон должно быть тривиальным.
import copy
import logging
class ColoredConsoleHandler(logging.StreamHandler):
def emit(self, record):
# Need to make a actual copy of the record
# to prevent altering the message for other loggers
myrecord = copy.copy(record)
levelno = myrecord.levelno
if (levelno >= 50): # CRITICAL / FATAL
color = '\x1b[31m' # red
elif (levelno >= 40): # ERROR
color = '\x1b[31m' # red
elif (levelno >= 30): # WARNING
color = '\x1b[33m' # yellow
elif (levelno >= 20): # INFO
color = '\x1b[32m' # green
elif (levelno >= 10): # DEBUG
color = '\x1b[35m' # pink
else: # NOTSET and anything else
color = '\x1b[0m' # normal
myrecord.msg = color + str(myrecord.msg) + '\x1b[0m' # normal
logging.StreamHandler.emit(self, myrecord)
Я обновил пример из тегов поддержки 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):
# can't do super(...) here because Formatter is an old school class
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
Большое улучшение. Однако комментарий о super относится только к какой-то древней версии Python, я думаю? Поскольку этот ответ с 2010 года. У меня он отлично работал с Python 2.7.
Еще один небольшой ремикс подхода airmind, который держит все в одном классе:
class ColorFormatter(logging.Formatter):
FORMAT = ("[$BOLD%(name)-20s$RESET][%(levelname)-18s] "
"%(message)s "
"($BOLD%(filename)s$RESET:%(lineno)d)")
BLACK, RED, GREEN, YELLOW, BLUE, MAGENTA, CYAN, WHITE = range(8)
RESET_SEQ = "\033[0m"
COLOR_SEQ = "\033[1;%dm"
BOLD_SEQ = "\033[1m"
COLORS = {
'WARNING': YELLOW,
'INFO': WHITE,
'DEBUG': BLUE,
'CRITICAL': YELLOW,
'ERROR': RED
}
def formatter_msg(self, msg, use_color = True):
if use_color:
msg = msg.replace("$RESET", self.RESET_SEQ).replace("$BOLD", self.BOLD_SEQ)
else:
msg = msg.replace("$RESET", "").replace("$BOLD", "")
return msg
def __init__(self, use_color=True):
msg = self.formatter_msg(self.FORMAT, use_color)
logging.Formatter.__init__(self, msg)
self.use_color = use_color
def format(self, record):
levelname = record.levelname
if self.use_color and levelname in self.COLORS:
fore_color = 30 + self.COLORS[levelname]
levelname_color = self.COLOR_SEQ % fore_color + levelname + self.RESET_SEQ
record.levelname = levelname_color
return logging.Formatter.format(self, record)
Чтобы использовать, прикрепите средство форматирования к обработчику, например:
handler.setFormatter(ColorFormatter())
logger.addHandler(handler)
У меня были проблемы с правильной настройкой форматтера:
class ColouredFormatter(logging.Formatter):
def __init__(self, msg):
logging.Formatter.__init__(self, msg)
self._init_colour = _get_colour()
def close(self):
# restore the colour information to what it was
_set_colour(self._init_colour)
def format(self, record):
# Add your own colourer based on the other examples
_set_colour( LOG_LEVEL_COLOUR[record.levelno] )
return logging.Formatter.format(self, record)
def init():
# Set up the formatter. Needs to be first thing done.
rootLogger = logging.getLogger()
hdlr = logging.StreamHandler()
fmt = ColouredFormatter('%(message)s')
hdlr.setFormatter(fmt)
rootLogger.addHandler(hdlr)
А затем использовать:
import coloured_log
import logging
coloured_log.init()
logging.info("info")
logging.debug("debug")
coloured_log.close() # restore colours
Это должен был быть псевдокод (так как _set_colour тоже отсутствует), но кое-что добавлено. Больше всего проблем было со знанием того, как правильно прикрепить форматтер.
См. Решение «домкрат-сантехник». Я думаю, что это лучший способ решить проблему (т.е. обработчик должен делать раскрашивание). stackoverflow.com/questions/384076/…
Посмотрите на следующее решение. Обработчик потока должен выполнять окраску, тогда у вас есть возможность окрашивать слова, а не только всю строку (с помощью Formatter).
http://plumberjack.blogspot.com/2010/12/colorizing-logging-output-in-terminals.html
Вы можете найти обновленную реализацию в этом суть (поддерживается автором блога). Пользуюсь и отлично работает. Спасибо, что поделился.
Быстрое и грязное решение для предопределенных уровней журнала и без определения нового класса.
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))
логирование импорта @ spiderplant0; # вставляем код из @ABC; попробуйте с помощью logging.warning («это тест»). Вы увидите, что часть «ВНИМАНИЕ: это тест» окрашена в верхний регистр. Он работает только на Linux, кстати
Поскольку окрашено только имя уровня журнала, вы должны убедиться, что имя уровня журнала вообще выводится на консоль. У меня такого не бывает из коробки. Что-нибудь в этом роде поможет: logging.basicConfig(format='%(asctime)s [%(name)s] [%(levelname)s] %(message)s') Где, конечно, важен %(levelnames)s.
Самое простое и понятное решение для применения и понимания.
Просто попробуйте в консоли Linux. echo -e "Normal texst \033[1;31mred bold text\033[0m normal text again". Параметр echo -e интерпретирует "\ 033" как восьмеричную форму символа Escape ASCII. Этот специальный символ заставляет некоторые совместимые терминалы интерпретировать последующие символы (включая char m) как специальные команды. en.wikipedia.org/wiki/ANSI_escape_code
Незначительное улучшение: поместите этот код в if sys.sdterr.isatty():. В этом случае, если вы перенаправляете вывод в файл, файл не будет содержать этих escape-символов.
Скажу, САМОЕ ЛУЧШЕЕ!
Просто ответил так же на аналогичный вопрос: Python | изменить цвет текста в оболочке
Идея в том, чтобы использовать библиотеку клинт. Который поддерживает оболочки MAC, Linux и Windows (CLI).
Несколько лет назад я написал цветной обработчик потока для собственного использования. Затем я наткнулся на эту страницу и нашел коллекцию фрагментов кода, которые люди копируют / вставляют :-(. Мой обработчик потока в настоящее время работает только в UNIX (Linux, Mac OS X), но преимущество в том, что это доступно на PyPI (и GitHub) и он очень прост в использовании и имеет режим синтаксиса Vim :-). В будущем я могу расширить его для работы в Windows.
Чтобы установить пакет:
$ pip install coloredlogs
Чтобы убедиться, что это работает:
$ coloredlogs --demo
Чтобы начать работу с вашим собственным кодом:
$ python
> import coloredlogs, logging
> coloredlogs.install()
> logging.info("It works!")
2014-07-30 21:21:26 peter-macbook root[7471] INFO It works!
Формат журнала по умолчанию, показанный в приведенном выше примере, содержит дату, время, имя хоста, имя регистратора, PID, уровень журнала и сообщение журнала. Вот как это выглядит на практике:

ПРИМЕЧАНИЕ. При использовании Git Bash с MinTTY
У Git Bash для Windows есть несколько задокументированных причуд: Winpty и Git Bash
Что для escape-кодов ANSI, а также для перезаписи символов и анимации в стиле ncurses вам нужно префикс команд с помощью winpty.
$ winpty coloredlogs --demo
$ winpty python your_colored_logs_script.py
как ни странно, я просто собирался добавить ссылку на "pypi.python.org/pypi/coloredlogs/0.4.7" в этой теме!
По какой-то причине при использовании AttributeError: 'module' object has no attribute 'install' у меня постоянно появляется coloredlogs.install(). Можете ли вы подтвердить это с помощью последней версии.
Это действительно выглядит красиво. К сожалению, это ломает многое; в частности, он аннулирует вызовы logging.basicConfig. Это делает невозможным, например, использование специального средства форматирования.
@ Клеман: Два (совпадающих?) Вопроса: (1) Что именно вы имеете в виду, говоря «аннулируют вызовы logging.basicConfig» и (2) какова была бы альтернатива? И logging.basicConfig(), и coloredlogs.install() устанавливают обработчик потока, который ведет журнал в консоли, поэтому без "аннулирования" вы получите дублирующиеся сообщения ...
Я ожидал либо волшебства для (1), либо (что более разумно) способа указать coloredlogs.install, какой формат использовать, как в пакете colorlog.
Спасибо за комментарий, @ Clément; Боюсь, для меня это нарушает условия сделки. Я рекомендую xolox или кому-либо еще исправить это, потому что подобная библиотека была бы полезна. К сожалению, в настоящее время я не в состоянии внести в него свой вклад.
К вашему сведению: в более новых версиях пакета цветных журналов используется настраиваемый модуль форматирования для вставки управляющих последовательностей ANSI. Это настраиваемое средство форматирования поддерживает определенные пользователем форматы журналов так же, как модуль ведения журнала Python. Однако я не понимаю, как цветные журналы могут быть объединены с определяемым пользователем средством форматирования, это противоречит дизайну пакета.
Если вы хотите использовать его вместе с регистратором тензорного потока, просто используйте coloredlogs.install(logger=tf.logging._get_logger())
проста в использовании .. но не может сохранять журналы в файл .. какой обходной путь?
Можем ли мы также записать это в файл?
Очень хорошо сделано!! и на сегодняшний день он работает в Windows как мечта :)
Установил, протестировал, не работает, удалил.
Теперь есть выпущенный модуль PyPi для настраиваемого вывода цветного журнала:
https://pypi.python.org/pypi/rainbow_logging_handler/
а также
https://github.com/laysakura/rainbow_logging_handler
Поддерживает Windows
Поддерживает Django
Настраиваемые цвета
Поскольку он распространяется как яйцо Python, его очень легко установить для любого приложения Python.
Обновлять: Поскольку это зуд, который я так долго хотел почесать, я пошел дальше и написал библиотеку для ленивых людей вроде меня, которым просто нужны простые способы делать что-то: зенлог
Colorlog отлично подходит для этого. Это доступно на PyPI (и, следовательно, его можно установить через pip install colorlog), а это активно поддерживается.
Вот небольшой фрагмент, который можно скопировать и вставить, чтобы настроить ведение журнала и распечатать прилично выглядящие сообщения журнала:
import logging
LOG_LEVEL = logging.DEBUG
LOGFORMAT = " %(log_color)s%(levelname)-8s%(reset)s | %(log_color)s%(message)s%(reset)s"
from colorlog import ColoredFormatter
logging.root.setLevel(LOG_LEVEL)
formatter = ColoredFormatter(LOGFORMAT)
stream = logging.StreamHandler()
stream.setLevel(LOG_LEVEL)
stream.setFormatter(formatter)
log = logging.getLogger('pythonConfig')
log.setLevel(LOG_LEVEL)
log.addHandler(stream)
log.debug("A quirky message only developers care about")
log.info("Curious users might want to know this")
log.warn("Something is wrong and any user should be informed")
log.error("Serious stuff, this is red for a reason")
log.critical("OH NO everything is on fire")
Выход:

Отличный ответ; +1. Хотя пример кода можно обрезать (действительно ли нужны три вызова setLevel?)
Я надеялся, что найду такой ответ, если буду долго искать ответы. ☺ Я надеюсь, что @airmind рассмотрит вопрос о том, чтобы сделать этот ответ принятым, чтобы будущие умные люди могли найти лучшую библиотеку с оптимальной ленью. ?
Я только что проголосовал за примеры сообщений OUTPUT ^^
Спасибо! Действительно полезно и работало для меня как шарм!
Вот мое решение:
class ColouredFormatter(logging.Formatter):
RESET = '\x1B[0m'
RED = '\x1B[31m'
YELLOW = '\x1B[33m'
BRGREEN = '\x1B[01;32m' # grey in solarized for terminals
def format(self, record, colour=False):
message = super().format(record)
if not colour:
return message
level_no = record.levelno
if level_no >= logging.CRITICAL:
colour = self.RED
elif level_no >= logging.ERROR:
colour = self.RED
elif level_no >= logging.WARNING:
colour = self.YELLOW
elif level_no >= logging.INFO:
colour = self.RESET
elif level_no >= logging.DEBUG:
colour = self.BRGREEN
else:
colour = self.RESET
message = colour + message + self.RESET
return message
class ColouredHandler(logging.StreamHandler):
def __init__(self, stream=sys.stdout):
super().__init__(stream)
def format(self, record, colour=False):
if not isinstance(self.formatter, ColouredFormatter):
self.formatter = ColouredFormatter()
return self.formatter.format(record, colour)
def emit(self, record):
stream = self.stream
try:
msg = self.format(record, stream.isatty())
stream.write(msg)
stream.write(self.terminator)
self.flush()
except Exception:
self.handleError(record)
h = ColouredHandler()
h.formatter = ColouredFormatter('{asctime} {levelname:8} {message}', '%Y-%m-%d %H:%M:%S', '{')
logging.basicConfig(level=logging.DEBUG, handlers=[h])
Используйте пижонство.
Пример:
print(pyfancy.RED + "Hello Red!" + pyfancy.END)
Вопрос состоял в том, чтобы настроить функциональность logging для использования отдельной библиотеки раскраски.
Хотя другие решения кажутся хорошими, у них есть некоторые проблемы. Некоторые окрашивают целые строки, что иногда не требуется, а некоторые опускают любую конфигурацию, которая может быть у вас все вместе. Приведенное ниже решение не влияет ни на что, кроме самого сообщения.
Код
class ColoredFormatter(logging.Formatter):
def format(self, record):
if record.levelno == logging.WARNING:
record.msg = '\033[93m%s\033[0m' % record.msg
elif record.levelno == logging.ERROR:
record.msg = '\033[91m%s\033[0m' % record.msg
return logging.Formatter.format(self, record)
Пример
logger = logging.getLogger('mylogger')
handler = logging.StreamHandler()
log_format = '[%(asctime)s]:%(levelname)-7s:%(message)s'
time_format = '%H:%M:%S'
formatter = ColoredFormatter(log_format, datefmt=time_format)
handler.setFormatter(formatter)
logger.addHandler(handler)
logger.warn('this should be yellow')
logger.error('this should be red')
Выход
[17:01:36]:WARNING:this should be yellow
[17:01:37]:ERROR :this should be red
Как видите, все остальное по-прежнему выводится и остается в своем исходном цвете. Если вы хотите изменить что-либо еще, кроме сообщения, вы можете просто передать цветовые коды в log_format в примере.
когда я его использую, сообщения печатаются дважды. ты знаешь почему?
@ не могли бы вы уточнить? А именно вы имеете в виду что-то вроде [17:01:36]:WARNING:this should be yellowthis should be yellow или целую строку, печатаемую дважды?
Извините за краткость комментария. Произошло первое: [17:01:36]: ВНИМАНИЕ: это должно быть желтым \ nэто должно быть желтым. Однако я хочу, чтобы отображался только отформатированный, иначе он выглядит как мусор из-за избыточных журналов.
@ MuratKarakuş не уверен, почему это происходит, не имея полного представления о реализации. Если вы используете настраиваемый регистратор, возможно, вы в какой-то момент мешаете? Быстрое исправление может заключаться в удалении 7s:%(message)s из log_format.
Мне нужно добавить две заявки, одна из которых раскрашивает только сообщение (ColoredFormatter), а другая раскрашивает всю строку (ColorizingStreamHandler). Они также включают больше цветовых кодов ANSI, чем предыдущие решения.
Некоторый контент был получен (с изменениями) из: Пост выше, и http://plumberjack.blogspot.com/2010/12/colorizing-logging-output-in-terminals.html.
Раскрашивает только сообщение:
class ColoredFormatter(logging.Formatter):
"""Special custom formatter for colorizing log messages!"""
BLACK = '\033[0;30m'
RED = '\033[0;31m'
GREEN = '\033[0;32m'
BROWN = '\033[0;33m'
BLUE = '\033[0;34m'
PURPLE = '\033[0;35m'
CYAN = '\033[0;36m'
GREY = '\033[0;37m'
DARK_GREY = '\033[1;30m'
LIGHT_RED = '\033[1;31m'
LIGHT_GREEN = '\033[1;32m'
YELLOW = '\033[1;33m'
LIGHT_BLUE = '\033[1;34m'
LIGHT_PURPLE = '\033[1;35m'
LIGHT_CYAN = '\033[1;36m'
WHITE = '\033[1;37m'
RESET = "\033[0m"
def __init__(self, *args, **kwargs):
self._colors = {logging.DEBUG: self.DARK_GREY,
logging.INFO: self.RESET,
logging.WARNING: self.BROWN,
logging.ERROR: self.RED,
logging.CRITICAL: self.LIGHT_RED}
super(ColoredFormatter, self).__init__(*args, **kwargs)
def format(self, record):
"""Applies the color formats"""
record.msg = self._colors[record.levelno] + record.msg + self.RESET
return logging.Formatter.format(self, record)
def setLevelColor(self, logging_level, escaped_ansi_code):
self._colors[logging_level] = escaped_ansi_code
Раскрашивает всю строку:
class ColorizingStreamHandler(logging.StreamHandler):
BLACK = '\033[0;30m'
RED = '\033[0;31m'
GREEN = '\033[0;32m'
BROWN = '\033[0;33m'
BLUE = '\033[0;34m'
PURPLE = '\033[0;35m'
CYAN = '\033[0;36m'
GREY = '\033[0;37m'
DARK_GREY = '\033[1;30m'
LIGHT_RED = '\033[1;31m'
LIGHT_GREEN = '\033[1;32m'
YELLOW = '\033[1;33m'
LIGHT_BLUE = '\033[1;34m'
LIGHT_PURPLE = '\033[1;35m'
LIGHT_CYAN = '\033[1;36m'
WHITE = '\033[1;37m'
RESET = "\033[0m"
def __init__(self, *args, **kwargs):
self._colors = {logging.DEBUG: self.DARK_GREY,
logging.INFO: self.RESET,
logging.WARNING: self.BROWN,
logging.ERROR: self.RED,
logging.CRITICAL: self.LIGHT_RED}
super(ColorizingStreamHandler, self).__init__(*args, **kwargs)
@property
def is_tty(self):
isatty = getattr(self.stream, 'isatty', None)
return isatty and isatty()
def emit(self, record):
try:
message = self.format(record)
stream = self.stream
if not self.is_tty:
stream.write(message)
else:
message = self._colors[record.levelno] + message + self.RESET
stream.write(message)
stream.write(getattr(self, 'terminator', '\n'))
self.flush()
except (KeyboardInterrupt, SystemExit):
raise
except:
self.handleError(record)
def setLevelColor(self, logging_level, escaped_ansi_code):
self._colors[logging_level] = escaped_ansi_code
import logging
import sys
colors = {'pink': '\033[95m', 'blue': '\033[94m', 'green': '\033[92m', 'yellow': '\033[93m', 'red': '\033[91m',
'ENDC': '\033[0m', 'bold': '\033[1m', 'underline': '\033[4m'}
logging.basicConfig(stream=sys.stdout, level=logging.DEBUG)
def str_color(color, data):
return colors[color] + str(data) + colors['ENDC']
params = {'param1': id1, 'param2': id2}
logging.info('\nParams:' + str_color("blue", str(params)))`
+1 Хороший пример с кодами [9*m для «ярких» цветов ANSI! P.S. Ваша последняя строчка меня немного беспокоит, потому что она еще не известна безопасно ли ведение журнала вне определения функции в Python.
Простой, но очень гибкий инструмент для раскрашивания ЛЮБОГО текста терминала - «расцветка».
pip install colout
myprocess | colout REGEX_WITH_GROUPS color1,color2...
Если любой текст в выводе myprocess, который соответствует группе 1 регулярного выражения, будет окрашен в цвет color1, группа 2 - в цвет2 и т. д.
Например:
tail -f /var/log/mylogfile | colout '^(\w+ \d+ [\d:]+)|(\w+\.py:\d+ .+\(\)): (.+)$' white,black,cyan bold,bold,normal
то есть первая группа регулярных выражений (parens) соответствует начальной дате в файле журнала, вторая группа соответствует имени файла Python, номеру строки и имени функции, а третья группа соответствует сообщению журнала, которое появляется после этого. Я также использую параллельную последовательность «жирный / нормальный», а также последовательность цветов. Это выглядит так:
Обратите внимание, что строки или части строк, которые не соответствуют ни одному из моих регулярных выражений, по-прежнему отображаются эхом, поэтому это не похоже на grep --color - из вывода ничего не фильтруется.
Очевидно, это достаточно гибко, чтобы вы могли использовать его с любым процессом, а не только с последующими лог-файлами. Обычно я просто создаю новое регулярное выражение на лету каждый раз, когда хочу что-то раскрасить. По этой причине я предпочитаю colout любому настраиваемому инструменту раскраски файлов журнала, потому что мне нужно изучить только один инструмент, независимо от того, что я раскрашиваю: ведение журнала, тестовый вывод, выделение синтаксиса фрагментов кода в терминале и т. д.
Он также позволяет избежать фактического сброса кодов ANSI в самом файле журнала, что IMHO является плохой идеей, потому что это нарушит такие вещи, как grepping для шаблонов в файле журнала, если вы всегда не помните, что коды ANSI в вашем регулярном выражении grep.
Вы можете импортировать модуль colorlog и использовать его ColoredFormatter для раскрашивания сообщений журнала.
Пластина для основного модуля:
import logging
import os
import sys
try:
import colorlog
except ImportError:
pass
def setup_logging():
root = logging.getLogger()
root.setLevel(logging.DEBUG)
format = '%(asctime)s - %(levelname)-8s - %(message)s'
date_format = '%Y-%m-%d %H:%M:%S'
if 'colorlog' in sys.modules and os.isatty(2):
cformat = '%(log_color)s' + format
f = colorlog.ColoredFormatter(cformat, date_format,
log_colors = { 'DEBUG' : 'reset', 'INFO' : 'reset',
'WARNING' : 'bold_yellow', 'ERROR': 'bold_red',
'CRITICAL': 'bold_red' })
else:
f = logging.Formatter(format, date_format)
ch = logging.StreamHandler()
ch.setFormatter(f)
root.addHandler(ch)
setup_logging()
log = logging.getLogger(__name__)
Код позволяет использовать цвета только в сообщениях журнала, если модуль colorlog установлен и если вывод действительно поступает на терминал. Это позволяет избежать записи управляющих последовательностей в файл при перенаправлении вывода журнала.
Кроме того, настраивается индивидуальная цветовая схема, которая лучше подходит для терминалов с темным фоном.
Некоторые примеры регистрации вызовов:
log.debug ('Hello Debug')
log.info ('Hello Info')
log.warn ('Hello Warn')
log.error ('Hello Error')
log.critical('Hello Critical')
Выход:
Также можно использовать colorlog.basicConfig вместо logging.basicConfig, у которого есть хорошие настройки по умолчанию.
К сведению, colorlog не всегда работает непосредственно на платформах Windows (как указано, требуется зависимость от colorama). Даже с этим у меня были проблемы с тем, чтобы заставить его работать в среде Anaconda / Spyder. Вам может потребоваться указать colorama.init (strip = False), например, в escape_code.py (как указано в этом потоке github.com/spyder-ide/spyder/issues/1917)
import logging
logging.basicConfig(filename = "f.log" filemode='w', level=logging.INFO,
format = "%(logger_name)s %(color)s %(message)s %(endColor)s")
class Logger(object):
__GREEN = "\033[92m"
__RED = '\033[91m'
__ENDC = '\033[0m'
def __init__(self, name):
self.logger = logging.getLogger(name)
self.extra = {'logger_name': name, 'endColor': self.__ENDC, 'color': self.__GREEN}
def info(self, msg):
self.extra['color'] = self.__GREEN
self.logger.info(msg, extra=self.extra)
def error(self, msg):
self.extra['color'] = self.__RED
self.logger.error(msg, extra=self.extra)
Logger("File Name").info("This shows green text")
Для консоли вы можете не указывать имя файла или просто имя файла = '' должно работать. измените basicConfig, чтобы включить другие свойства, такие как номер файла, модуль ..
Еще одно решение с цветами ZetaSyanthis:
def config_log(log_level):
def set_color(level, code):
level_fmt = "\033[1;" + str(code) + "m%s\033[1;0m"
logging.addLevelName( level, level_fmt % logging.getLevelName(level) )
std_stream = sys.stdout
isatty = getattr(std_stream, 'isatty', None)
if isatty and isatty():
levels = [logging.DEBUG, logging.CRITICAL, logging.WARNING, logging.ERROR]
for idx, level in enumerate(levels):
set_color(level, 30 + idx )
set_color(logging.DEBUG, 0)
logging.basicConfig(stream=std_stream, level=log_level)
вызовите его один раз из функции __main__. У меня там что-то вроде этого:
options, arguments = p.parse_args()
log_level = logging.DEBUG if options.verbose else logging.WARNING
config_log(log_level)
он также проверяет, является ли вывод консолью, иначе цвета не используются.
Что ж, думаю, я мог бы добавить свой вариант цветного регистратора.
В этом нет ничего необычного, но он очень прост в использовании и не меняет объект записи, что позволяет избежать записи управляющих последовательностей ANSI в файл журнала, если используется обработчик файлов. Это не влияет на форматирование сообщений журнала.
Если вы уже используете модуль форматирования журнала, все, что вам нужно сделать, чтобы получить цветные имена уровней, - это заменить обработчики ваших консультантов Formatter на ColoredFormatter. Если вы регистрируете все приложение, вам нужно сделать это только для регистратора верхнего уровня.
цветной_log.py
#!/usr/bin/env python
from copy import copy
from logging import Formatter
MAPPING = {
'DEBUG' : 37, # white
'INFO' : 36, # cyan
'WARNING' : 33, # yellow
'ERROR' : 31, # red
'CRITICAL': 41, # white on red bg
}
PREFIX = '\033['
SUFFIX = '\033[0m'
class ColoredFormatter(Formatter):
def __init__(self, patern):
Formatter.__init__(self, patern)
def format(self, record):
colored_record = copy(record)
levelname = colored_record.levelname
seq = MAPPING.get(levelname, 37) # default white
colored_levelname = ('{0}{1}m{2}{3}') \
.format(PREFIX, seq, levelname, SUFFIX)
colored_record.levelname = colored_levelname
return Formatter.format(self, colored_record)
app.py
#!/usr/bin/env python
import logging
from colored_log import ColoredFormatter
# Create top level logger
log = logging.getLogger("main")
# Add console handler using our custom ColoredFormatter
ch = logging.StreamHandler()
ch.setLevel(logging.DEBUG)
cf = ColoredFormatter("[%(name)s][%(levelname)s] %(message)s (%(filename)s:%(lineno)d)")
ch.setFormatter(cf)
log.addHandler(ch)
# Add file handler
fh = logging.FileHandler('app.log')
fh.setLevel(logging.DEBUG)
ff = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
fh.setFormatter(ff)
log.addHandler(fh)
# Set log level
log.setLevel(logging.DEBUG)
# Log some stuff
log.debug("app has started")
log.info("Logging to 'app.log' in the script dir")
log.warning("This is my last warning, take heed")
log.error("This is an error")
log.critical("He's dead, Jim")
# Import a sub-module
import sub_module
sub_module.py
#!/usr/bin/env python
import logging
log = logging.getLogger('main.sub_module')
log.debug("Hello from the sub module")
Терминальный выход

app.log содержание
2017-09-29 00:32:23,434 - main - DEBUG - app has started
2017-09-29 00:32:23,434 - main - INFO - Logging to 'app.log' in the script dir
2017-09-29 00:32:23,435 - main - WARNING - This is my last warning, take heed
2017-09-29 00:32:23,435 - main - ERROR - This is an error
2017-09-29 00:32:23,435 - main - CRITICAL - He's dead, Jim
2017-09-29 00:32:23,435 - main.sub_module - DEBUG - Hello from the sub module
Конечно, вы можете сделать все, что захотите, с форматированием вывода файлов терминала и журнала. Раскрашивается только уровень журнала.
Я надеюсь, что кто-то сочтет это полезным, и это не совсем то же самое. :)
Файлы примеров Python можно загрузить из этого GitHub Gist: https://gist.github.com/KurtJacobson/48e750701acec40c7161b5a2f79e6bfd
Кстати, чтобы добавить цвета к самому сообщению, просто добавьте эту строку перед return: colored_record.msg = ('{0}{1}m{2}{3}').format(self.PREFIX, seq, colored_record.getMessage(), self.SUFFIX)
Есть масса отзывов. Но никто не говорит о декораторах. Итак, вот мой.
Потому что это намного проще.
Не нужно ничего ни импортировать, ни писать подклассы:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import logging
NO_COLOR = "\33[m"
RED, GREEN, ORANGE, BLUE, PURPLE, LBLUE, GREY = \
map("\33[%dm".__mod__, range(31, 38))
logging.basicConfig(format = "%(message)s", level=logging.DEBUG)
logger = logging.getLogger(__name__)
# the decorator to apply on the logger methods info, warn, ...
def add_color(logger_method, color):
def wrapper(message, *args, **kwargs):
return logger_method(
# the coloring is applied here.
color+message+NO_COLOR,
*args, **kwargs
)
return wrapper
for level, color in zip((
"info", "warn", "error", "debug"), (
GREEN, ORANGE, RED, BLUE
)):
setattr(logger, level, add_color(getattr(logger, level), color))
# this is displayed in red.
logger.error("Launching %s." % __file__)
При этом ошибки будут отображаться красным цветом, сообщения отладки - синим и т. д. Как и задано в вопросе.
Мы могли бы даже адаптировать оболочку, чтобы она принимала аргумент color, чтобы динамически устанавливать цвет сообщения с помощью logger.debug("message", color=GREY).
Обновлено: Итак, вот адаптированный декоратор для установки цветов во время выполнения:
def add_color(logger_method, _color):
def wrapper(message, *args, **kwargs):
color = kwargs.pop("color", _color)
if isinstance(color, int):
color = "\33[%dm" % color
return logger_method(
# the coloring is applied here.
color+message+NO_COLOR,
*args, **kwargs
)
return wrapper
# blah blah, apply the decorator...
# this is displayed in red.
logger.error("Launching %s." % __file__)
# this is displayed in blue
logger.error("Launching %s." % __file__, color=34)
# and this, in grey
logger.error("Launching %s." % __file__, color=GREY)
Это Enum, содержащий цветовые коды:
class TerminalColour:
"""
Terminal colour formatting codes
"""
# https://stackoverflow.com/questions/287871/print-in-terminal-with-colors
MAGENTA = '\033[95m'
BLUE = '\033[94m'
GREEN = '\033[92m'
YELLOW = '\033[93m'
RED = '\033[91m'
GREY = '\033[0m' # normal
WHITE = '\033[1m' # bright white
UNDERLINE = '\033[4m'
Это может применяться к имена каждого уровня журнала. Имейте в виду, что это чудовищный взлом.
logging.addLevelName(logging.INFO, "{}{}{}".format(TerminalColour.WHITE, logging.getLevelName(logging.INFO), TerminalColour.GREY))
logging.addLevelName(logging.WARNING, "{}{}{}".format(TerminalColour.YELLOW, logging.getLevelName(logging.WARNING), TerminalColour.GREY))
logging.addLevelName(logging.ERROR, "{}{}{}".format(TerminalColour.RED, logging.getLevelName(logging.ERROR), TerminalColour.GREY))
logging.addLevelName(logging.CRITICAL, "{}{}{}".format(TerminalColour.MAGENTA, logging.getLevelName(logging.CRITICAL), .GREY))
Обратите внимание, что ваше средство форматирования журнала должно включать название уровня журнала.
%(levelname)
Например:
LOGGING = {
...
'verbose': {
'format': '%(asctime)s %(levelname)s %(name)s:%(lineno)s %(module)s %(process)d %(thread)d %(message)s'
},
'simple': {
'format': '[%(asctime)s] %(levelname)s %(name)s %(message)s'
},
Определить класс
import logging
class CustomFormatter(logging.Formatter):
"""Logging Formatter to add colors and count warning / errors"""
grey = "\x1b[38;21m"
yellow = "\x1b[33;21m"
red = "\x1b[31;21m"
bold_red = "\x1b[31;1m"
reset = "\x1b[0m"
format = "%(asctime)s - %(name)s - %(levelname)s - %(message)s (%(filename)s:%(lineno)d)"
FORMATS = {
logging.DEBUG: grey + format + reset,
logging.INFO: grey + format + reset,
logging.WARNING: yellow + format + reset,
logging.ERROR: red + format + reset,
logging.CRITICAL: bold_red + format + reset
}
def format(self, record):
log_fmt = self.FORMATS.get(record.levelno)
formatter = logging.Formatter(log_fmt)
return formatter.format(record)
Создать экземпляр регистратора
# create logger with 'spam_application'
logger = logging.getLogger("My_app")
logger.setLevel(logging.DEBUG)
# create console handler with a higher log level
ch = logging.StreamHandler()
ch.setLevel(logging.DEBUG)
ch.setFormatter(CustomFormatter())
logger.addHandler(ch)
И пользуйся!
logger.debug("debug message")
logger.info("info message")
logger.warning("warning message")
logger.error("error message")
logger.critical("critical message")
Для окон
Это решение работает на Mac OS, IDE-терминалах. Похоже, в командной строке Windows по умолчанию вообще нет цветов. Вот инструкции по их включению, которые я не пробовал https://www.howtogeek.com/322432/how-to-customize-your-command-prompts-color-scheme-with-microsofts-colortool/
Я запускаю тест (python 3.7, windows), но в журнале не отображаются цвета: ←[38;21m2019-11-12 19:29:50,994 - My_app - DEBUG - debug message (test_colored_log.py:43)←[0m ←[38;21m2019-11-12 19:29:50,994 - My_app - INFO - info message (test_colored_log.py:44)←[0m ←[33;21m2019-11-12 19:29:50,994 - My_app - WARNING - warning message (test_colored_log.py:45)←[0m ←[31;21m2019-11-12 19:29:50,994 - My_app - ERROR - error message (test_colored_log.py:46)←[0m ←[31;1m2019-11-12 19:29:50,994 - My_app - CRITICAL - critical message (test_colored_log.py:47)←[0m
Мне настолько понравился этот ответ, что я сделал для него репо с несколькими приращениями и шпаргалкой цветов ansi.
@constructor где вы его запускаете? Консоль IDE? оконный терминал?
@ Джо, что именно не работает? какая у вас среда и какие ошибки вы получаете? Я бы хотел пересмотреть решение, чтобы оно работало на разных платформах.
@SergeyPleshakov Я снова тестировал в терминале Visual Studio Code, и теперь он работает, но не работает в командной строке Windows: [38;21m2020-06-03 21:12:46,363 [INFO ] [algo] info[0m [33;21m2020-06-03 21:12:46,363 [WARNING] [algo] warning [algo.py:18][0m [31;21m2020-06-03 21:12:46,363 [ERROR ] [algo] error[0m [38;21m2020-06-03 21:12:46,364 [INFO ] [algo] result: None[0m
@constructor рад, что это сработало для вас. Постараюсь доработать ответ для поддержки ОС windows
Привет, я запустил это на Ubuntu и работает. Единственное, что это добавляет двойное подчеркивание в моем терминале, какие-либо мысли по этому поводу?
Ой, просто поигрался с этим и нашел решение, просто замените ...21m на 20m, похоже, у меня все работает идеально. На всякий случай у кого-то такая же проблема.
@DarrenChristopher - это решение, которое вы упомянули для окон?
@SergeyPleshakov Проверено на Ubuntu. Сообщите мне, если это не сработает в Windows.
@SergeyPleshakov Приятно видеть, что вы повторно использовали часть моего кода (вы получили сообщение "и подсчет предупреждений / ошибок") :) Рад, что это помогло сообществу! (и он был разработан для Windows ... но я использовал colorama.Fore для получения цветовых кодов.
FriendlyLog - еще одна альтернатива. Он работает с Python 2 и 3 под Linux, Windows и MacOS.
С нетерпением жду нового PR, чтобы уменьшить беспорядок на пути модуля
Следующее решение работает только с python 3, но для меня оно выглядит наиболее понятным.
Идея состоит в том, чтобы использовать фабрику записей журнала для добавления «цветных» атрибутов к объектам записей журнала, а затем использовать эти «цветные» атрибуты в формате журнала.
import logging
logger = logging.getLogger(__name__)
def configure_logging(level):
# add 'levelname_c' attribute to log resords
orig_record_factory = logging.getLogRecordFactory()
log_colors = {
logging.DEBUG: "\033[1;34m", # blue
logging.INFO: "\033[1;32m", # green
logging.WARNING: "\033[1;35m", # magenta
logging.ERROR: "\033[1;31m", # red
logging.CRITICAL: "\033[1;41m", # red reverted
}
def record_factory(*args, **kwargs):
record = orig_record_factory(*args, **kwargs)
record.levelname_c = "{}{}{}".format(
log_colors[record.levelno], record.levelname, "\033[0m")
return record
logging.setLogRecordFactory(record_factory)
# now each log record object would contain 'levelname_c' attribute
# and you can use this attribute when configuring logging using your favorite
# method.
# for demo purposes I configure stderr log right here
formatter_c = logging.Formatter("[%(asctime)s] %(levelname_c)s:%(name)s:%(message)s")
stderr_handler = logging.StreamHandler()
stderr_handler.setLevel(level)
stderr_handler.setFormatter(formatter_c)
root_logger = logging.getLogger('')
root_logger.setLevel(logging.DEBUG)
root_logger.addHandler(stderr_handler)
def main():
configure_logging(logging.DEBUG)
logger.debug("debug message")
logger.info("info message")
logger.critical("something unusual happened")
if __name__ == '__main__':
main()
Вы можете легко изменить этот пример, чтобы создать другие цветные атрибуты (например, message_c), а затем использовать эти атрибуты для получения цветного текста (только) там, где вы хотите.
(удобный трюк, который я обнаружил недавно: у меня есть файл с цветными журналами отладки, и всякий раз, когда я хочу временно увеличить уровень журнала моего приложения, я просто tail -f файл журнала в другом терминале и вижу журналы отладки на экране без изменения какой-либо конфигурации и перезапуска заявление)
Это еще один вариант Python3 примера airmind. Мне нужны были некоторые особенности, которых я не видел в других примерах.
Примечания: Я использовал колорама, но вы можете изменить его, чтобы он не требовался. Также для моего тестирования я просто запускал файл python, поэтому мой класс находится в модуле __main__. Вам нужно будет изменить (): __main__.ColoredFormatter на любой ваш модуль.
pip install colorama pyyaml
logging.yaml
---
version: 1
disable_existing_loggers: False
formatters:
simple:
format: "%(threadName)s - %(name)s - %(levelname)s - %(message)s"
color:
format: "%(threadName)s - %(name)s - %(levelname)s - %(message)s"
(): __main__.ColoredFormatter
use_color: true
handlers:
console:
class: logging.StreamHandler
level: DEBUG
formatter: color
stream: ext://sys.stdout
info_file_handler:
class: logging.handlers.RotatingFileHandler
level: INFO
formatter: simple
filename: app.log
maxBytes: 20971520
backupCount: 20
encoding: utf8
error_file_handler:
class: logging.handlers.RotatingFileHandler
level: ERROR
formatter: simple
filename: errors.log
maxBytes: 10485760
backupCount: 20
encoding: utf8
root:
level: DEBUG
handlers: [console, info_file_handler, error_file_handler]
main.py
import logging
import logging.config
import os
from logging import Logger
import colorama
import yaml
from colorama import Back, Fore, Style
COLORS = {
"WARNING": Fore.YELLOW,
"INFO": Fore.CYAN,
"DEBUG": Fore.BLUE,
"CRITICAL": Fore.YELLOW,
"ERROR": Fore.RED,
}
class ColoredFormatter(logging.Formatter):
def __init__(self, *, format, use_color):
logging.Formatter.__init__(self, fmt=format)
self.use_color = use_color
def format(self, record):
msg = super().format(record)
if self.use_color:
levelname = record.levelname
if hasattr(record, "color"):
return f"{record.color}{msg}{Style.RESET_ALL}"
if levelname in COLORS:
return f"{COLORS[levelname]}{msg}{Style.RESET_ALL}"
return msg
with open("logging.yaml", "rt") as f:
config = yaml.safe_load(f.read())
logging.config.dictConfig(config)
logger: Logger = logging.getLogger(__name__)
logger.info("Test INFO", extra = {"color": Back.RED})
logger.info("Test INFO", extra = {"color": f"{Style.BRIGHT}{Back.RED}"})
logger.info("Test INFO")
logger.debug("Test DEBUG")
logger.warning("Test WARN")
выход:
Как насчет выделения аргументов сообщения журнала с чередованием цветов в дополнение к раскраске по уровням? Недавно я написал для этого простой код. Еще одно преимущество заключается в том, что вызов журнала выполняется с форматированием в стиле скобок Python 3. ("{}").
См. Последний код и примеры здесь: https://github.com/davidohana/colargulog
Пример кода регистрации:
root_logger = logging.getLogger()
console_handler = logging.StreamHandler(stream=sys.stdout)
console_format = "%(asctime)s - %(levelname)-8s - %(name)-25s - %(message)s"
colored_formatter = ColorizedArgsFormatter(console_format)
console_handler.setFormatter(colored_formatter)
root_logger.addHandler(console_handler)
logger = logging.getLogger(__name__)
logger.info("Hello World")
logger.info("Request from {} handled in {:.3f} ms", socket.gethostname(), 11)
logger.info("Request from {} handled in {:.3f} ms", "127.0.0.1", 33.1)
logger.info("My favorite drinks are {}, {}, {}, {}", "milk", "wine", "tea", "beer")
logger.debug("this is a {} message", logging.getLevelName(logging.DEBUG))
logger.info("this is a {} message", logging.getLevelName(logging.INFO))
logger.warning("this is a {} message", logging.getLevelName(logging.WARNING))
logger.error("this is a {} message", logging.getLevelName(logging.ERROR))
logger.critical("this is a {} message", logging.getLevelName(logging.CRITICAL))
logger.info("Does old-style formatting also work? %s it is, but no colors (yet)", True)
Выход:
Выполнение:
"""
colargulog - Python3 Logging with Colored Arguments and new string formatting style
Written by [email protected]
License: Apache-2.0
"""
import logging
import logging.handlers
import re
class ColorCodes:
grey = "\x1b[38;21m"
green = "\x1b[1;32m"
yellow = "\x1b[33;21m"
red = "\x1b[31;21m"
bold_red = "\x1b[31;1m"
blue = "\x1b[1;34m"
light_blue = "\x1b[1;36m"
purple = "\x1b[1;35m"
reset = "\x1b[0m"
class ColorizedArgsFormatter(logging.Formatter):
arg_colors = [ColorCodes.purple, ColorCodes.light_blue]
level_fields = ["levelname", "levelno"]
level_to_color = {
logging.DEBUG: ColorCodes.grey,
logging.INFO: ColorCodes.green,
logging.WARNING: ColorCodes.yellow,
logging.ERROR: ColorCodes.red,
logging.CRITICAL: ColorCodes.bold_red,
}
def __init__(self, fmt: str):
super().__init__()
self.level_to_formatter = {}
def add_color_format(level: int):
color = ColorizedArgsFormatter.level_to_color[level]
_format = fmt
for fld in ColorizedArgsFormatter.level_fields:
search = "(%\(" + fld + "\).*?s)"
_format = re.sub(search, f"{color}\\1{ColorCodes.reset}", _format)
formatter = logging.Formatter(_format)
self.level_to_formatter[level] = formatter
add_color_format(logging.DEBUG)
add_color_format(logging.INFO)
add_color_format(logging.WARNING)
add_color_format(logging.ERROR)
add_color_format(logging.CRITICAL)
@staticmethod
def rewrite_record(record: logging.LogRecord):
if not BraceFormatStyleFormatter.is_brace_format_style(record):
return
msg = record.msg
msg = msg.replace("{", "_{{")
msg = msg.replace("}", "_}}")
placeholder_count = 0
# add ANSI escape code for next alternating color before each formatting parameter
# and reset color after it.
while True:
if "_{{" not in msg:
break
color_index = placeholder_count % len(ColorizedArgsFormatter.arg_colors)
color = ColorizedArgsFormatter.arg_colors[color_index]
msg = msg.replace("_{{", color + "{", 1)
msg = msg.replace("_}}", "}" + ColorCodes.reset, 1)
placeholder_count += 1
record.msg = msg.format(*record.args)
record.args = []
def format(self, record):
orig_msg = record.msg
orig_args = record.args
formatter = self.level_to_formatter.get(record.levelno)
self.rewrite_record(record)
formatted = formatter.format(record)
# restore log record to original state for other handlers
record.msg = orig_msg
record.args = orig_args
return formatted
class BraceFormatStyleFormatter(logging.Formatter):
def __init__(self, fmt: str):
super().__init__()
self.formatter = logging.Formatter(fmt)
@staticmethod
def is_brace_format_style(record: logging.LogRecord):
if len(record.args) == 0:
return False
msg = record.msg
if '%' in msg:
return False
count_of_start_param = msg.count("{")
count_of_end_param = msg.count("}")
if count_of_start_param != count_of_end_param:
return False
if count_of_start_param != len(record.args):
return False
return True
@staticmethod
def rewrite_record(record: logging.LogRecord):
if not BraceFormatStyleFormatter.is_brace_format_style(record):
return
record.msg = record.msg.format(*record.args)
record.args = []
def format(self, record):
orig_msg = record.msg
orig_args = record.args
self.rewrite_record(record)
formatted = self.formatter.format(record)
# restore log record to original state for other handlers
record.msg = orig_msg
record.args = orig_args
return formatted
Удобный сценарий bash с цветами tput
# Simple using tput
bold=$(tput bold)
reset=$(tput sgr0)
fblack=$(tput setaf 0)
fred=$(tput setaf 1)
fgreen=$(tput setaf 2)
fyellow=$(tput setaf 3)
fblue=$(tput setaf 4)
fmagenta=$(tput setaf 5)
fcyan=$(tput setaf 6)
fwhite=$(tput setaf 7)
fnotused=$(tput setaf 8)
freset=$(tput setaf 9)
bblack=$(tput setab 0)
bred=$(tput setab 1)
bgreen=$(tput setab 2)
byellow=$(tput setab 3)
bblue=$(tput setab 4)
bmagenta=$(tput setab 5)
bcyan=$(tput setab 6)
bwhite=$(tput setab 7)
bnotused=$(tput setab 8)
breset=$(tput setab 9)
# 0 - Emergency (emerg) $fred # something is wrong... go red
# 1 - Alerts (alert) $fred # something is wrong... go red
# 2 - Critical (crit) $fred # something is wrong... go red
# 3 - Errors (err) $fred # something is wrong... go red
# 4 - Warnings (warn) $fyellow # yellow yellow dirty logs
# 5 - Notification (notice) $fwhite # common stuff
# 6 - Information (info) $fblue # sky is blue
# 7 - Debug (debug) $fgreen # lot of stuff to read... go green
Установите пакет colorlog, вы можете сразу же использовать цвета в сообщениях журнала:
logger, как обычно.DEBUG
и INFO напрямую из модуля регистрации.ColoredFormatter
библиотекой colorlog.import colorlog
logger = colorlog.getLogger()
logger.setLevel(colorlog.colorlog.logging.DEBUG)
handler = colorlog.StreamHandler()
handler.setFormatter(colorlog.ColoredFormatter())
logger.addHandler(handler)
logger.debug("Debug message")
logger.info("Information message")
logger.warning("Warning message")
logger.error("Error message")
logger.critical("Critical message")
Просто обновите ColoredFormatter:
handler.setFormatter(colorlog.ColoredFormatter('%(log_color)s [%(asctime)s] %(levelname)s [%(filename)s.%(funcName)s:%(lineno)d] %(message)s', datefmt='%a, %d %b %Y %H:%M:%S'))
Упаковка:
pip install colorlog
выход:
Collecting colorlog
Downloading colorlog-4.6.2-py2.py3-none-any.whl (10.0 kB)
Installing collected packages: colorlog
Successfully installed colorlog-4.6.2
Вы должны указать, что хотите мультиплатформенное решение - как для Linux, так и для Windows.