我如何着色Python日志输出?

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

现在,Python拥有logging模块,它可以让你指定很多选项来自定义输出。 所以,我在想像Python可能会有类似的东西,但我无法找到如何在任何地方做到这一点。

有什么办法让Python logging模块输出颜色?

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

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

任何想法如何使用日志记录模块获得彩色输出?


我已经知道颜色逃逸,前一段时间我在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 = "33[0m"
COLOR_SEQ = "33[1;%dm"
BOLD_SEQ = "33[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)

以防万一其他人需要它。

如果您使用多个记录器或处理程序,请注意: ColoredFormatter正在更改记录对象,该对象将进一步传递给其他处理程序或传播到其他记录器。 如果您已配置文件记录器等,则可能不希望在日志文件中包含颜色。 为了避免这种情况,最好在操作levelname属性之前用copy.copy()简单地创建一个record副本,或者在返回格式化的字符串(在评论中信任Michael copy.copy()之前将levelname重置为先前的值。


几年前,我为自己的用途写了一个彩色的流处理程序。 然后我偶然发现了这个页面,发现了一些人们正在复制/粘贴的代码片段:-(。我的流处理程序目前只能在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,日志级别和日志消息。 这是实践中的样子:

coloredlogs输出的屏幕截图


这是一个适用于任何平台的解决方案。 如果它不只是告诉我,我会更新它。

它是如何工作的:在支持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())
链接地址: http://www.djcxy.com/p/15261.html

上一篇: How can I color Python logging output?

下一篇: Formula to determine brightness of RGB color