前段时间,我看到一个Mono应用程序的输出是彩色的,可能是因为它的日志系统(因为所有的消息都是标准化的)。

现在,Python有了日志记录模块,它允许您指定许多选项来定制输出。所以,我想象类似的事情可能与Python,但我不知道如何在任何地方做到这一点。

是否有办法使Python日志模块输出为彩色?

我想要的(例如)错误显示为红色,调试消息显示为蓝色或黄色,等等。

当然,这可能需要一个兼容的终端(大多数现代终端都是);但如果不支持颜色,我可以退回到原始的日志输出。

有什么想法,我可以得到彩色输出与日志模块?


当前回答

如果有人正在寻找一个漂亮的着色以及自定义日志级别着色,你可以看看这个改编的解决方案(它使用moecololelibrary):

#Install moecolor
pip install moecolor
from moecolor import FormatText as ft

class ConsoleFormatter(logging.Formatter):
    default_format = f"[%(asctime)s | %(name)s | %(funcName)s | LN%(lineno)s | %(levelname)s]: %(message)s"
    time_portion =  ft('%(asctime)s', color='purple').text
    format_portion = ' | %(name)s | %(funcName)s | LN%(lineno)d | %(levelname)s]: '
    FORMATS = {
        'DEBUG': time_portion + ft(format_portion, color='yellow').text + ft('%(message)s', color='fff9ae').text,
        'INFO': time_portion + ft(format_portion, color='green').text + ft('%(message)s', color='#d3ffb3').text,
        'WARNING': time_portion + ft(format_portion, color='orange').text + ft('%(message)s', color='#ffc100').text,
        'TIMER': time_portion + ft(format_portion, color='blue').text + ft('%(message)s', color='#00b4d8').text, # Note, this is a custom log level
        'ERROR': time_portion + ft(format_portion, color='red').text + ft('%(message)s', color='#ba262b').text,
        'CRITICAL': time_portion + ft(format_portion, color='#8D0101').text + ft('%(message)s', color='#D5212E').text,
    }

    def format(self, record):
        _format = self.FORMATS.get(record.levelname, self.default_format)
        formatter = logging.Formatter(_format)
        return formatter.format(record)

你可以这样使用它:

console_handler = logging.StreamHandler()
console_handler.setFormatter(ConsoleFormatter())

其他回答

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)

使用

日志记录器("文件名").info("显示绿色文本")

我已经知道了颜色转义,我使用他们在我的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)

要使用它,请创建自己的Logger:

# 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)

以防有人需要。

Be careful if you're using more than one logger or handler: ColoredFormatter is changing the record object, which is passed further to other handlers or propagated to other loggers. If you have configured file loggers etc. you probably don't want to have the colors in the log files. To avoid that, it's probably best to simply create a copy of record with copy.copy() before manipulating the levelname attribute, or to reset the levelname to the previous value, before returning the formatted string (credit to Michael in the comments).

这是airmind示例的另一个Python3变体。我想要一些在其他例子中没有看到的特性

为终端使用颜色,但不要在文件处理程序中写入不可打印的字符(我为此定义了2个格式化器) 能够覆盖特定日志消息的颜色 从一个文件(在本例中是yaml)配置记录器

注意:我使用了colorama,但是你可以修改它,这样就不需要了。对于我的测试,我只是运行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")

输出:

快速和肮脏的解决方案预定义的日志级别,而不定义一个新的类。

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))

使用龙卷风库

Tornado web框架提供了一些实用程序,包括Tornado .log. logformatter格式化程序,它可以在没有框架其他部分的情况下使用。

对不支持ANSI颜色代码的Windows版本的颜色支持是通过使用colorama库启用的。希望使用它的应用程序必须首先调用colorama.init来初始化colorama。

import logging
import tornado.log
# import colorama  # uncomment on some Windows versions
# colorama.init()

consoleHandler = logging.StreamHandler()
consoleHandler.setFormatter(tornado.log.LogFormatter())
logging.basicConfig(level=logging.DEBUG, handlers=[consoleHandler])
logger = logging.getLogger("test")
logger.info("hello world")