我如何着色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,日志级别和日志消息。 这是实践中的样子:
这是一个适用于任何平台的解决方案。 如果它不只是告诉我,我会更新它。
它是如何工作的:在支持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