前段时间,我看到一个Mono应用程序的输出是彩色的,可能是因为它的日志系统(因为所有的消息都是标准化的)。
现在,Python有了日志记录模块,它允许您指定许多选项来定制输出。所以,我想象类似的事情可能与Python,但我不知道如何在任何地方做到这一点。
是否有办法使Python日志模块输出为彩色?
我想要的(例如)错误显示为红色,调试消息显示为蓝色或黄色,等等。
当然,这可能需要一个兼容的终端(大多数现代终端都是);但如果不支持颜色,我可以退回到原始的日志输出。
有什么想法,我可以得到彩色输出与日志模块?
这是@Sergey Pleshakov的出色回答的轻微变化,他只对关卡使用颜色,并像预期的那样使用basicConfig:
class CustomFormatter(logging.Formatter):
white = "\x1b[97;20m"
grey = "\x1b[38;20m"
green = "\x1b[32;20m"
cyan = "\x1b[36;20m"
yellow = "\x1b[33;20m"
red = "\x1b[31;20m"
bold_red = "\x1b[31;1m"
reset = "\x1b[0m"
fmt = "%(asctime)s - {}%(levelname)-8s{} - %(name)s.%(funcName)s - %(message)s"
FORMATS = {
logging.DEBUG: fmt.format(grey, reset),
logging.INFO: fmt.format(green, reset),
logging.WARNING: fmt.format(yellow, reset),
logging.ERROR: fmt.format(red, reset),
logging.CRITICAL: fmt.format(bold_red, reset),
}
def format(self, record):
log_fmt = self.FORMATS.get(record.levelno)
formatter = logging.Formatter(log_fmt, datefmt="%H:%M:%S")
return formatter.format(record)
handler = logging.StreamHandler()
handler.setFormatter(CustomFormatter())
logging.basicConfig(
level=logging.DEBUG,
handlers=[handler]
)
使用丰富的库
Rich提供了一个日志处理程序,它将对Python日志模块编写的文本进行格式化和着色。
它很容易使用和可定制+工作在cmd.exe, Windows终端,ConEmu和Jupyter笔记本!(我告诉你,我试过很多包,只有rich的颜色在笔记本上有用。)
Rich还带有许多其他奇特的功能。
安装
pip install rich
最小的例子:
import logging
from rich.logging import RichHandler
FORMAT = "%(message)s"
logging.basicConfig(
level="NOTSET", format=FORMAT, datefmt="[%X]", handlers=[RichHandler()]
) # set level=20 or logging.INFO to turn of debug
logger = logging.getLogger("rich")
logger.debug("debug...")
logger.info("info...")
logger.warning("warning...")
logger.error("error...")
logger.fatal("fatal...")
如果有人正在寻找一个漂亮的着色以及自定义日志级别着色,你可以看看这个改编的解决方案(它使用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())
下面的解决方案只适用于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()
您可以轻松地修改此示例,以创建其他彩色属性(f.e. message_c),然后使用这些属性(仅)在需要的位置获取彩色文本。
(我最近发现的一个方便的技巧:我有一个带有彩色调试日志的文件,每当我想临时增加我的应用程序的日志级别时,我只需在不同的终端中跟踪-f日志文件,并在屏幕上看到调试日志,w/o更改任何配置并重新启动应用程序)