Как я могу раскрасить вывод журнала Python?

Некоторое время назад я видел приложение Mono с цветным выводом, предположительно из-за его системы журналов (поскольку все сообщения были стандартизированы).

Теперь в Python есть модуль logging, который позволяет указать множество параметров для настройки вывода. Итак, я представляю себе нечто подобное с Python, но я нигде не могу найти, как это сделать.

Есть ли способ сделать вывод модуля Python logging в цвете?

То, что мне нужно (например), ошибки - красным, отладочные сообщения - синим или желтым и так далее.

Конечно, для этого, вероятно, потребуется совместимый терминал (в большинстве современных терминалов); но я мог бы вернуться к исходному выводу logging, если цвет не поддерживается.

Есть идеи, как я могу получить цветной вывод с помощью модуля регистрации?

Вы должны указать, что хотите мультиплатформенное решение - как для Linux, так и для Windows.

sorin 25.08.2009 22:55

Связано, если вы используете Eclipse / PyDev: Раскрашиваем журналы в консоли eclipse

Tobias Kienzler 16.11.2012 13:18

Возможно, вы также можете использовать colorlog

Ehtesh Choudhury 15.02.2014 01:19

запустите pip install ipython и добавьте alias python = "ipython" в сценарий запуска оболочки (например, ~/.bashrc для оболочки bash)

Alexandre Holden Daly 14.07.2014 19:25

Вы также можете попробовать хромалог, который я написал для поддержки всех операционных систем и версий Python (2.7 и 3. *)

ereOn 15.05.2015 01:08

Решения, которые на самом деле сбрасывают коды ANSI в файл журнала, являются плохой идеей, они поймают вас, когда вы будете искать что-то через шесть месяцев, но забудете разрешить символы ANSI в своем шаблоне регулярного выражения. Ниже приведены некоторые решения, которые добавляют цвет при просмотре журнала, а не во время его записи ...

Jonathan Hartley 07.05.2016 16:10

FriendlyLog (github.com/SebiSebi/friendlylog) - еще одна альтернатива. Он работает с Python 2 и 3 под Linux, Windows и MacOS.

SebiSebi 06.10.2019 19:44

@JonathanHartley Это причина, по которой вы устанавливаете несколько обработчиков журналов. Вы можете настроить StreamHandler ведения журнала для отправки вывода журнала в потоки, такие как sys.stdout и / или sys.stderr Обработчики, отправляющие в stdout / stderr, можно раскрасить, этот вывод существует только в окне терминала. Затем вы настраиваете другой обработчик журнала, который отправляет выходные данные журнала в файл журнала (и не окрашивает сообщения).

Matt Conway 10.03.2020 17:23

для этого вам даже не нужны пакеты, посмотрите stackoverflow.com/a/56944256/9150146

Sergey Pleshakov 21.05.2020 21:34

если вы хотите включить цвет только тогда, когда stdout является терминалом: stackoverflow.com/questions/1077113/…

Florian Castellane 20.03.2021 10:20
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
385
10
192 081
31

Ответы 31

Я уже знал о цветовом экранировании, я использовал их в своей командной строке 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 C H 22.05.2009 20:20

@Swaroop - это escape-коды ANSI, которые вы можете прочитать в Google или найти здесь: en.wikipedia.org/wiki/ANSI_escape_code, или, альтернативно, pueblo.sourceforge.net/doc/manual/ansi_color_codes.html

Brian M. Hunt 17.08.2009 00:56

Я не верю, что вам следует создавать подкласс регистратора только для этого - ваш ответ хорош, если вы создадите специализированный Formatter и укажете его использование на StreamHandler. Но нет необходимости в подклассе регистратора. Фактически, использование класса регистратора добавляет обработчик к каждому созданному регистратору, что обычно не является тем, что вам нужно.

Vinay Sajip 17.08.2009 16:17

@Vinay - не могли бы вы подробнее рассказать, как это реализовать?

simon 21.03.2012 04:28

@simon: plumberjack.blogspot.co.uk/2010/12/…

Vinay Sajip 23.03.2012 03:08

Одно примечание к ColoredFormatter. Он изменяет объект записи, который передается другим обработчикам или распространяется на другие регистраторы. Если вы настроили регистраторы файлов и т. д., Вы, вероятно, не захотите иметь цвета в файлах журнала. Чтобы избежать этого, вероятно, лучше всего просто создать копию record с copy.copy() перед манипулированием атрибутом levelname или сбросить имя уровня на предыдущее значение перед возвратом отформатированной строки.

Michael 20.04.2013 17:31

Вот решение, которое должно работать на любой платформе. Если это не так, просто скажите мне, и я обновлю его.

Как это работает: на платформе, поддерживающей 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.

mooware 15.06.2014 04:06

это сработало для меня! строка 90: должно быть args[1].msg = color + str(args[1].msg) + '\x1b[0m' # normal.

Rasika Perera 25.04.2015 20:25

Мне нравится это решение. использую его в настоящее время. Я вижу, что есть атрибут _set_color, есть ли способ сделать это для конкретного сообщения журнала? редактировать, видите ли, это просто патч для оконных машин. было бы неплохо добавить кастом для разных вариантов использования.

brizz 26.05.2015 02:15

+1 для цвета ANSI. В xterm вы можете даже получить 256 цветов за раз, и вы можете динамически определять палитру! Обратите внимание, однако, что все вызовы функций регистрации должны быть внутри определения функции, чтобы избежать потенциального Проблемы с блокировкой импорта при входе в систему вне определения функции. Ваш код выглядит в основном хорошо; меня беспокоит только то, что есть в TestColorer.py.

personal_cloud 23.09.2017 08:36

Это приводит к цветовым кодам в начале и конце сообщений журнала в реальных файлах журнала.

MehmedB 17.07.2019 10:26

Могу ли я оставить строку сообщения нормального цвета и раскрасить только секцию date, filename linenumber с левой стороны?

alper 03.06.2020 15:59

Я изменил исходный пример, предоставленный Сорином, и создал подкласс от 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.

Joakim 12.10.2015 17:20

Еще один небольшой ремикс подхода 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 тоже отсутствует), но кое-что добавлено. Больше всего проблем было со знанием того, как правильно прикрепить форматтер.

Nick 14.01.2011 16:55

См. Решение «домкрат-сантехник». Я думаю, что это лучший способ решить проблему (т.е. обработчик должен делать раскрашивание). stackoverflow.com/questions/384076/…

Nick 14.01.2011 16:56

Посмотрите на следующее решение. Обработчик потока должен выполнять окраску, тогда у вас есть возможность окрашивать слова, а не только всю строку (с помощью Formatter).

http://plumberjack.blogspot.com/2010/12/colorizing-logging-output-in-terminals.html

Вы можете найти обновленную реализацию в этом суть (поддерживается автором блога). Пользуюсь и отлично работает. Спасибо, что поделился.

noisebleed 15.04.2012 02:52

Быстрое и грязное решение для предопределенных уровней журнала и без определения нового класса.

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, кстати

Riccardo Galli 30.01.2014 03:39

Поскольку окрашено только имя уровня журнала, вы должны убедиться, что имя уровня журнала вообще выводится на консоль. У меня такого не бывает из коробки. Что-нибудь в этом роде поможет: logging.basicConfig(format='%(asctime)s [%(name)s] [%(levelname)s] %(message)s') Где, конечно, важен %(levelnames)s.

Sebastian 26.04.2016 17:23

Самое простое и понятное решение для применения и понимания.

F. Santiago 01.05.2017 15:20

Просто попробуйте в консоли 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

eugene-bright 11.07.2018 03:39

Незначительное улучшение: поместите этот код в if sys.sdterr.isatty():. В этом случае, если вы перенаправляете вывод в файл, файл не будет содержать этих escape-символов.

lesnik 20.09.2018 21:44

Скажу, САМОЕ ЛУЧШЕЕ!

Marek Gancarz 13.08.2020 23:04

Просто ответил так же на аналогичный вопрос: Python | изменить цвет текста в оболочке

Идея в том, чтобы использовать библиотеку клинт. Который поддерживает оболочки MAC, Linux и Windows (CLI).

Несколько лет назад я написал цветной обработчик потока для собственного использования. Затем я наткнулся на эту страницу и нашел коллекцию фрагментов кода, которые люди копируют / вставляют :-(. Мой обработчик потока в настоящее время работает только в UNIX (Linux, Mac OS X), но преимущество в том, что это доступно на PyPIGitHub) и он очень прост в использовании и имеет режим синтаксиса 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, уровень журнала и сообщение журнала. Вот как это выглядит на практике:

Screenshot of coloredlogs output

ПРИМЕЧАНИЕ. При использовании 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" в этой теме!

Iosu S. 04.03.2014 19:29

По какой-то причине при использовании AttributeError: 'module' object has no attribute 'install' у меня постоянно появляется coloredlogs.install(). Можете ли вы подтвердить это с помощью последней версии.

con-f-use 01.12.2015 19:23

Это действительно выглядит красиво. К сожалению, это ломает многое; в частности, он аннулирует вызовы logging.basicConfig. Это делает невозможным, например, использование специального средства форматирования.

Clément 15.12.2015 02:36

@ Клеман: Два (совпадающих?) Вопроса: (1) Что именно вы имеете в виду, говоря «аннулируют вызовы logging.basicConfig» и (2) какова была бы альтернатива? И logging.basicConfig(), и coloredlogs.install() устанавливают обработчик потока, который ведет журнал в консоли, поэтому без "аннулирования" вы получите дублирующиеся сообщения ...

xolox 15.12.2015 14:12

Я ожидал либо волшебства для (1), либо (что более разумно) способа указать coloredlogs.install, какой формат использовать, как в пакете colorlog.

Clément 15.12.2015 22:16

Спасибо за комментарий, @ Clément; Боюсь, для меня это нарушает условия сделки. Я рекомендую xolox или кому-либо еще исправить это, потому что подобная библиотека была бы полезна. К сожалению, в настоящее время я не в состоянии внести в него свой вклад.

Michael Scheper 27.07.2017 21:43

К вашему сведению: в более новых версиях пакета цветных журналов используется настраиваемый модуль форматирования для вставки управляющих последовательностей ANSI. Это настраиваемое средство форматирования поддерживает определенные пользователем форматы журналов так же, как модуль ведения журнала Python. Однако я не понимаю, как цветные журналы могут быть объединены с определяемым пользователем средством форматирования, это противоречит дизайну пакета.

xolox 27.07.2017 23:29

Если вы хотите использовать его вместе с регистратором тензорного потока, просто используйте coloredlogs.install(logger=tf.logging._get_logger())

Ido_f 05.06.2018 11:15

проста в использовании .. но не может сохранять журналы в файл .. какой обходной путь?

KawaiKx 24.11.2019 18:00

Можем ли мы также записать это в файл?

alper 31.01.2020 01:39

Очень хорошо сделано!! и на сегодняшний день он работает в Windows как мечта :)

SkyWalker 09.04.2020 17:20

Установил, протестировал, не работает, удалил.

Thomas Wana 01.04.2021 14:19

Теперь есть выпущенный модуль 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")

Выход:

Colorlog output

Отличный ответ; +1. Хотя пример кода можно обрезать (действительно ли нужны три вызова setLevel?)

Clément 15.12.2015 02:46

Я надеялся, что найду такой ответ, если буду долго искать ответы. ☺ Я надеюсь, что @airmind рассмотрит вопрос о том, чтобы сделать этот ответ принятым, чтобы будущие умные люди могли найти лучшую библиотеку с оптимальной ленью. ?

Michael Scheper 27.07.2017 21:48

Я только что проголосовал за примеры сообщений OUTPUT ^^

Agustin Barrachina 02.04.2020 16:39

Спасибо! Действительно полезно и работало для меня как шарм!

Orposuser 13.09.2020 23:06

Вот мое решение:

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 для использования отдельной библиотеки раскраски.

0xInfection 30.06.2019 13:21

Хотя другие решения кажутся хорошими, у них есть некоторые проблемы. Некоторые окрашивают целые строки, что иногда не требуется, а некоторые опускают любую конфигурацию, которая может быть у вас все вместе. Приведенное ниже решение не влияет ни на что, кроме самого сообщения.

Код

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 в примере.

когда я его использую, сообщения печатаются дважды. ты знаешь почему?

Validus Oculus 15.10.2016 11:28

@ не могли бы вы уточнить? А именно вы имеете в виду что-то вроде [17:01:36]:WARNING:this should be yellowthis should be yellow или целую строку, печатаемую дважды?

Pithikos 15.10.2016 13:05

Извините за краткость комментария. Произошло первое: [17:01:36]: ВНИМАНИЕ: это должно быть желтым \ nэто должно быть желтым. Однако я хочу, чтобы отображался только отформатированный, иначе он выглядит как мусор из-за избыточных журналов.

Validus Oculus 15.10.2016 13:15

@ MuratKarakuş не уверен, почему это происходит, не имея полного представления о реализации. Если вы используете настраиваемый регистратор, возможно, вы в какой-то момент мешаете? Быстрое исправление может заключаться в удалении 7s:%(message)s из log_format.

Pithikos 15.10.2016 13:50

Мне нужно добавить две заявки, одна из которых раскрашивает только сообщение (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.

personal_cloud 23.09.2017 08:43

Простой, но очень гибкий инструмент для раскрашивания ЛЮБОГО текста терминала - «расцветка».

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, номеру строки и имени функции, а третья группа соответствует сообщению журнала, которое появляется после этого. Я также использую параллельную последовательность «жирный / нормальный», а также последовательность цветов. Это выглядит так:

logfile with colored formatting

Обратите внимание, что строки или части строк, которые не соответствуют ни одному из моих регулярных выражений, по-прежнему отображаются эхом, поэтому это не похоже на 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, у которого есть хорошие настройки по умолчанию.

MarSoft 20.08.2017 01:11

К сведению, colorlog не всегда работает непосредственно на платформах Windows (как указано, требуется зависимость от colorama). Даже с этим у меня были проблемы с тем, чтобы заставить его работать в среде Anaconda / Spyder. Вам может потребоваться указать colorama.init (strip = False), например, в escape_code.py (как указано в этом потоке github.com/spyder-ide/spyder/issues/1917)

Matt-Mac-Muffin 02.01.2018 17:23
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, чтобы включить другие свойства, такие как номер файла, модуль ..

estifanos gebrehiwot 28.02.2017 23:24

Еще одно решение с цветами 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")

Полученные результаты

Терминальный выход

Terminal output

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)

The Godfather 19.06.2019 12:48

Есть масса отзывов. Но никто не говорит о декораторах. Итак, вот мой.

Потому что это намного проще.

Не нужно ничего ни импортировать, ни писать подклассы:

#!/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'
        },

Решение 2021 года, дополнительных пакетов не требуется, Python 3

Определить класс

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

constructor 12.11.2019 20:30

Мне настолько понравился этот ответ, что я сделал для него репо с несколькими приращениями и шпаргалкой цветов ansi.

Teodoro 01.05.2020 00:34

@constructor где вы его запускаете? Консоль IDE? оконный терминал?

Sergey Pleshakov 03.06.2020 16:44

@ Джо, что именно не работает? какая у вас среда и какие ошибки вы получаете? Я бы хотел пересмотреть решение, чтобы оно работало на разных платформах.

Sergey Pleshakov 03.06.2020 16:45

@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 03.06.2020 21:13

@constructor рад, что это сработало для вас. Постараюсь доработать ответ для поддержки ОС windows

Sergey Pleshakov 04.06.2020 00:45

Привет, я запустил это на Ubuntu и работает. Единственное, что это добавляет двойное подчеркивание в моем терминале, какие-либо мысли по этому поводу?

Darren Christopher 03.12.2020 06:25

Ой, просто поигрался с этим и нашел решение, просто замените ...21m на 20m, похоже, у меня все работает идеально. На всякий случай у кого-то такая же проблема.

Darren Christopher 03.12.2020 06:27

@DarrenChristopher - это решение, которое вы упомянули для окон?

Sergey Pleshakov 03.12.2020 16:18

@SergeyPleshakov Проверено на Ubuntu. Сообщите мне, если это не сработает в Windows.

Darren Christopher 04.12.2020 04:32

@SergeyPleshakov Приятно видеть, что вы повторно использовали часть моего кода (вы получили сообщение "и подсчет предупреждений / ошибок") :) Рад, что это помогло сообществу! (и он был разработан для Windows ... но я использовал colorama.Fore для получения цветовых кодов.

Jean-Francois T. 25.02.2021 14:22

FriendlyLog - еще одна альтернатива. Он работает с Python 2 и 3 под Linux, Windows и MacOS.

С нетерпением жду нового PR, чтобы уменьшить беспорядок на пути модуля

mbspark 18.02.2020 01:23

Следующее решение работает только с 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. Мне нужны были некоторые особенности, которых я не видел в других примерах.

  • использовать цвета для терминала, но не записывать непечатаемые символы в обработчики файлов (я определил для этого 2 средства форматирования)
  • возможность переопределить цвет для определенного сообщения журнала
  • настроить регистратор из файла (в данном случае yaml)

Примечания: Я использовал колорама, но вы можете изменить его, чтобы он не требовался. Также для моего тестирования я просто запускал файл 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")

выход:

output

Как насчет выделения аргументов сообщения журнала с чередованием цветов в дополнение к раскраске по уровням? Недавно я написал для этого простой код. Еще одно преимущество заключается в том, что вызов журнала выполняется с форматированием в стиле скобок 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

Другие вопросы по теме