前段时间,我看到一个Mono应用程序的输出是彩色的,可能是因为它的日志系统(因为所有的消息都是标准化的)。
现在,Python有了日志记录模块,它允许您指定许多选项来定制输出。所以,我想象类似的事情可能与Python,但我不知道如何在任何地方做到这一点。
是否有办法使Python日志模块输出为彩色?
我想要的(例如)错误显示为红色,调试消息显示为蓝色或黄色,等等。
当然,这可能需要一个兼容的终端(大多数现代终端都是);但如果不支持颜色,我可以退回到原始的日志输出。
有什么想法,我可以得到彩色输出与日志模块?
一个简单但非常灵活的工具为任何终端文本着色是'colout'。
pip install colout
myprocess | colout REGEX_WITH_GROUPS color1,color2...
其中'myprocess'输出中的任何匹配正则表达式第1组的文本都将用color1着色,第2组用color2着色,等等。
例如:
tail -f /var/log/mylogfile | colout '^(\w+ \d+ [\d:]+)|(\w+\.py:\d+ .+\(\)): (.+)$' white,black,cyan bold,bold,normal
也就是说,第一个正则表达式组(parens)匹配日志文件中的初始日期,第二组匹配python文件名、行号和函数名,第三组匹配其后的日志消息。我还使用了“粗体/法线”的平行序列以及颜色序列。这看起来像:
请注意,不匹配任何正则表达式的行或行的一部分仍然被回显,因此这与'grep——color'不同——输出中没有过滤掉任何内容。
显然,这是足够灵活的,您可以将它用于任何进程,而不仅仅是跟踪日志文件。每当我想给一些东西上色时,我通常只是快速地创建一个新的正则表达式。出于这个原因,我更喜欢colout而不是任何自定义日志文件着色工具,因为我只需要学习一种工具,不管我在为什么着色:日志记录、测试输出、在终端中突出显示代码片段的语法等等。
它还避免了在日志文件本身中实际转储ANSI代码,恕我说这是一个坏主意,因为它会破坏日志文件中的grepping模式之类的事情,除非您始终记得在grep正则表达式中匹配ANSI代码。
下面的解决方案只适用于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更改任何配置并重新启动应用程序)
我遇到的麻烦是正确设置格式化程序:
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