如何为Python日志输出上色?

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

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

有没有办法使Python logging模块输出为彩色?

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

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

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

282476 次浏览

我已经知道了颜色转义,我在不久前的bash提示中使用了它们。谢谢。< br > 我想要的是将它与日志模块集成在一起,经过几次尝试和错误后,我最终做到了 这是我最终得到的:

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)

以防有人需要。

如果使用多个记录器或处理程序,请小心:ColoredFormatter正在更改记录对象,该对象将进一步传递给其他处理程序或传播给其他记录器。如果你已经配置了文件记录器等,你可能不想在日志文件中有颜色。为了避免这种情况,最好是在操作levelname属性之前用copy.copy()创建一个record的副本,或者在返回格式化的字符串之前将levelname重置为前一个值(注释中要感谢迈克尔)。

下面是一个适用于任何平台的解决方案。如果没有,告诉我,我会更新的。

它是如何工作的:在支持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())

我修改了Sorin提供的原始的例子,并将StreamHandler子类化为ColorizedConsoleHandler

他们的解决方案的缺点是它修改了消息,并且因为修改了实际的日志消息,任何其他处理程序也将得到修改后的消息。

在我们的例子中,这导致日志文件中有颜色代码,因为我们使用了多个记录器。

下面的类只在支持ANSI的平台上工作,但是向它添加Windows颜色代码应该很简单。

import copy
import logging




class ColoredConsoleHandler(logging.StreamHandler):
def emit(self, record):
# Need to make a actual copy of the record
# to prevent altering the message for other loggers
myrecord = copy.copy(record)
levelno = myrecord.levelno
if(levelno >= 50):  # CRITICAL / FATAL
color = '\x1b[31m'  # red
elif(levelno >= 40):  # ERROR
color = '\x1b[31m'  # red
elif(levelno >= 30):  # WARNING
color = '\x1b[33m'  # yellow
elif(levelno >= 20):  # INFO
color = '\x1b[32m'  # green
elif(levelno >= 10):  # DEBUG
color = '\x1b[35m'  # pink
else:  # NOTSET and anything else
color = '\x1b[0m'  # normal
myrecord.msg = color + str(myrecord.msg) + '\x1b[0m'  # normal
logging.StreamHandler.emit(self, myrecord)
我更新了从airmind支持前景和背景标签的例子。 只需在日志格式化器字符串中使用颜色变量$BLACK - $WHITE即可。设置背景只需使用$BG-BLACK - $BG-WHITE.

import logging


BLACK, RED, GREEN, YELLOW, BLUE, MAGENTA, CYAN, WHITE = range(8)


COLORS = {
'WARNING'  : YELLOW,
'INFO'     : WHITE,
'DEBUG'    : BLUE,
'CRITICAL' : YELLOW,
'ERROR'    : RED,
'RED'      : RED,
'GREEN'    : GREEN,
'YELLOW'   : YELLOW,
'BLUE'     : BLUE,
'MAGENTA'  : MAGENTA,
'CYAN'     : CYAN,
'WHITE'    : WHITE,
}


RESET_SEQ = "\033[0m"
COLOR_SEQ = "\033[1;%dm"
BOLD_SEQ  = "\033[1m"


class ColorFormatter(logging.Formatter):


def __init__(self, *args, **kwargs):
# can't do super(...) here because Formatter is an old school class
logging.Formatter.__init__(self, *args, **kwargs)


def format(self, record):
levelname = record.levelname
color     = COLOR_SEQ % (30 + COLORS[levelname])
message   = logging.Formatter.format(self, record)
message   = message.replace("$RESET", RESET_SEQ)\
.replace("$BOLD",  BOLD_SEQ)\
.replace("$COLOR", color)
for k,v in COLORS.items():
message = message.replace("$" + k,    COLOR_SEQ % (v+30))\
.replace("$BG" + k,  COLOR_SEQ % (v+40))\
.replace("$BG-" + k, COLOR_SEQ % (v+40))
return message + RESET_SEQ


logging.ColorFormatter = ColorFormatter

所以现在你可以在配置文件中简单地执行以下操作:

[formatter_colorFormatter]
class=logging.ColorFormatter
format= $COLOR%(levelname)s $RESET %(asctime)s $BOLD$COLOR%(name)s$RESET %(message)s

airmind的另一种方法是将所有东西都放在一个类中:

class ColorFormatter(logging.Formatter):
FORMAT = ("[$BOLD%(name)-20s$RESET][%(levelname)-18s]  "
"%(message)s "
"($BOLD%(filename)s$RESET:%(lineno)d)")


BLACK, RED, GREEN, YELLOW, BLUE, MAGENTA, CYAN, WHITE = range(8)


RESET_SEQ = "\033[0m"
COLOR_SEQ = "\033[1;%dm"
BOLD_SEQ = "\033[1m"


COLORS = {
'WARNING': YELLOW,
'INFO': WHITE,
'DEBUG': BLUE,
'CRITICAL': YELLOW,
'ERROR': RED
}


def formatter_msg(self, msg, use_color = True):
if use_color:
msg = msg.replace("$RESET", self.RESET_SEQ).replace("$BOLD", self.BOLD_SEQ)
else:
msg = msg.replace("$RESET", "").replace("$BOLD", "")
return msg


def __init__(self, use_color=True):
msg = self.formatter_msg(self.FORMAT, use_color)
logging.Formatter.__init__(self, msg)
self.use_color = use_color


def format(self, record):
levelname = record.levelname
if self.use_color and levelname in self.COLORS:
fore_color = 30 + self.COLORS[levelname]
levelname_color = self.COLOR_SEQ % fore_color + levelname + self.RESET_SEQ
record.levelname = levelname_color
return logging.Formatter.format(self, record)

要使用将格式化程序附加到处理程序,如下所示:

handler.setFormatter(ColorFormatter())
logger.addHandler(handler)

我遇到的麻烦是正确设置格式化程序:

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

请看下面的解决方案。流处理程序应该是做着色的事情,然后你可以选择着色单词而不仅仅是整行(与Formatter)。

http://plumberjack.blogspot.com/2010/12/colorizing-logging-output-in-terminals.html

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

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

刚刚回答了类似的问题:在shell中更改文本颜色

其思想是使用克林特库。它支持MAC, Linux和Windows shell (CLI)。

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

截图of coloredlogs output

注意:当使用Git Bash与MinTTY

Git Bash在windows上有一些记录的怪癖: Winpty和Git Bash < / p >

对于ANSI转义代码和ncurses风格的字符重写和动画,你需要用winpty作为命令的前缀。

$ winpty coloredlogs --demo
$ winpty python your_colored_logs_script.py

现在有一个发布的PyPi模块,用于自定义彩色日志输出:

https://pypi.python.org/pypi/rainbow_logging_handler/ < a href = " https://pypi.python.org/pypi/rainbow_logging_handler/ " > < / >

而且

https://github.com/laysakura/rainbow_logging_handler < a href = " https://github.com/laysakura/rainbow_logging_handler " > < / >

  • 支持Windows

  • 支持Django

  • 可定制的颜色

由于它是作为Python卵分发的,因此非常容易为任何Python应用程序安装它。

更新:因为这是我一直想要挠的痒,所以我继续写了一个库,为像我这样只想要简单方法做事的懒人:zenlog

Colorlog在这方面非常出色。它是可在PyPI上使用(因此可以通过pip install colorlog安装),并且是积极维护

下面是一个快速复制粘贴代码片段,用于设置日志记录和打印像样的日志消息:

import logging
LOG_LEVEL = logging.DEBUG
LOGFORMAT = "  %(log_color)s%(levelname)-8s%(reset)s | %(log_color)s%(message)s%(reset)s"
from colorlog import ColoredFormatter
logging.root.setLevel(LOG_LEVEL)
formatter = ColoredFormatter(LOGFORMAT)
stream = logging.StreamHandler()
stream.setLevel(LOG_LEVEL)
stream.setFormatter(formatter)
log = logging.getLogger('pythonConfig')
log.setLevel(LOG_LEVEL)
log.addHandler(stream)


log.debug("A quirky message only developers care about")
log.info("Curious users might want to know this")
log.warn("Something is wrong and any user should be informed")
log.error("Serious stuff, this is red for a reason")
log.critical("OH NO everything is on fire")

输出:

Colorlog output

以下是我的解决方案:

class ColouredFormatter(logging.Formatter):
RESET = '\x1B[0m'
RED = '\x1B[31m'
YELLOW = '\x1B[33m'
BRGREEN = '\x1B[01;32m'  # grey in solarized for terminals


def format(self, record, colour=False):
message = super().format(record)


if not colour:
return message


level_no = record.levelno
if level_no >= logging.CRITICAL:
colour = self.RED
elif level_no >= logging.ERROR:
colour = self.RED
elif level_no >= logging.WARNING:
colour = self.YELLOW
elif level_no >= logging.INFO:
colour = self.RESET
elif level_no >= logging.DEBUG:
colour = self.BRGREEN
else:
colour = self.RESET


message = colour + message + self.RESET


return message




class ColouredHandler(logging.StreamHandler):
def __init__(self, stream=sys.stdout):
super().__init__(stream)


def format(self, record, colour=False):
if not isinstance(self.formatter, ColouredFormatter):
self.formatter = ColouredFormatter()


return self.formatter.format(record, colour)


def emit(self, record):
stream = self.stream
try:
msg = self.format(record, stream.isatty())
stream.write(msg)
stream.write(self.terminator)
self.flush()
except Exception:
self.handleError(record)




h = ColouredHandler()
h.formatter = ColouredFormatter('{asctime} {levelname:8} {message}', '%Y-%m-%d %H:%M:%S', '{')
logging.basicConfig(level=logging.DEBUG, handlers=[h])

使用pyfancy

例子:

print(pyfancy.RED + "Hello Red!" + pyfancy.END)

虽然其他解决方案看起来不错,但它们存在一些问题。有些人会给整条线上色,有时这是不需要的,有些人会省略你可能在一起的任何配置。下面的解决方案只影响消息本身。

代码

class ColoredFormatter(logging.Formatter):
def format(self, record):
if record.levelno == logging.WARNING:
record.msg = '\033[93m%s\033[0m' % record.msg
elif record.levelno == logging.ERROR:
record.msg = '\033[91m%s\033[0m' % record.msg
return logging.Formatter.format(self, record)

例子

logger = logging.getLogger('mylogger')
handler = logging.StreamHandler()


log_format = '[%(asctime)s]:%(levelname)-7s:%(message)s'
time_format = '%H:%M:%S'
formatter = ColoredFormatter(log_format, datefmt=time_format)
handler.setFormatter(formatter)
logger.addHandler(handler)


logger.warn('this should be yellow')
logger.error('this should be red')

输出

[17:01:36]:WARNING:this should be yellow
[17:01:37]:ERROR  :this should be red

如您所见,其他所有内容仍然输出并保持初始颜色。如果你想改变消息以外的任何东西,你可以简单地将颜色代码传递给例子中的log_format

我有两个提交要添加,其中一个只着色消息(ColoredFormatter),另一个着色整行(ColorizingStreamHandler)。与以前的解决方案相比,这些方案还包括更多的ANSI颜色代码。

部分内容来自(经过修改): 上面的帖子,和http://plumberjack.blogspot.com/2010/12/colorizing-logging-output-in-terminals.html.

只给信息上色:

class ColoredFormatter(logging.Formatter):
"""Special custom formatter for colorizing log messages!"""


BLACK = '\033[0;30m'
RED = '\033[0;31m'
GREEN = '\033[0;32m'
BROWN = '\033[0;33m'
BLUE = '\033[0;34m'
PURPLE = '\033[0;35m'
CYAN = '\033[0;36m'
GREY = '\033[0;37m'


DARK_GREY = '\033[1;30m'
LIGHT_RED = '\033[1;31m'
LIGHT_GREEN = '\033[1;32m'
YELLOW = '\033[1;33m'
LIGHT_BLUE = '\033[1;34m'
LIGHT_PURPLE = '\033[1;35m'
LIGHT_CYAN = '\033[1;36m'
WHITE = '\033[1;37m'


RESET = "\033[0m"


def __init__(self, *args, **kwargs):
self._colors = {logging.DEBUG: self.DARK_GREY,
logging.INFO: self.RESET,
logging.WARNING: self.BROWN,
logging.ERROR: self.RED,
logging.CRITICAL: self.LIGHT_RED}
super(ColoredFormatter, self).__init__(*args, **kwargs)


def format(self, record):
"""Applies the color formats"""
record.msg = self._colors[record.levelno] + record.msg + self.RESET
return logging.Formatter.format(self, record)


def setLevelColor(self, logging_level, escaped_ansi_code):
self._colors[logging_level] = escaped_ansi_code

为整行上色:

class ColorizingStreamHandler(logging.StreamHandler):


BLACK = '\033[0;30m'
RED = '\033[0;31m'
GREEN = '\033[0;32m'
BROWN = '\033[0;33m'
BLUE = '\033[0;34m'
PURPLE = '\033[0;35m'
CYAN = '\033[0;36m'
GREY = '\033[0;37m'


DARK_GREY = '\033[1;30m'
LIGHT_RED = '\033[1;31m'
LIGHT_GREEN = '\033[1;32m'
YELLOW = '\033[1;33m'
LIGHT_BLUE = '\033[1;34m'
LIGHT_PURPLE = '\033[1;35m'
LIGHT_CYAN = '\033[1;36m'
WHITE = '\033[1;37m'


RESET = "\033[0m"


def __init__(self, *args, **kwargs):
self._colors = {logging.DEBUG: self.DARK_GREY,
logging.INFO: self.RESET,
logging.WARNING: self.BROWN,
logging.ERROR: self.RED,
logging.CRITICAL: self.LIGHT_RED}
super(ColorizingStreamHandler, self).__init__(*args, **kwargs)


@property
def is_tty(self):
isatty = getattr(self.stream, 'isatty', None)
return isatty and isatty()


def emit(self, record):
try:
message = self.format(record)
stream = self.stream
if not self.is_tty:
stream.write(message)
else:
message = self._colors[record.levelno] + message + self.RESET
stream.write(message)
stream.write(getattr(self, 'terminator', '\n'))
self.flush()
except (KeyboardInterrupt, SystemExit):
raise
except:
self.handleError(record)


def setLevelColor(self, logging_level, escaped_ansi_code):
self._colors[logging_level] = escaped_ansi_code
import logging
import sys


colors = {'pink': '\033[95m', 'blue': '\033[94m', 'green': '\033[92m', 'yellow': '\033[93m', 'red': '\033[91m',
'ENDC': '\033[0m', 'bold': '\033[1m', 'underline': '\033[4m'}


logging.basicConfig(stream=sys.stdout, level=logging.DEBUG)




def str_color(color, data):
return colors[color] + str(data) + colors['ENDC']


params = {'param1': id1, 'param2': id2}


logging.info('\nParams:' + str_color("blue", str(params)))`

'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文件名、行号和函数名,第三组匹配其后的日志消息。我还使用了“粗体/法线”的平行序列以及颜色序列。这看起来像:

logfile with colored formatting .

请注意,不匹配任何正则表达式的行或行的一部分仍然被回显,因此这与'grep——color'不同——输出中没有过滤掉任何内容。

显然,这是足够灵活的,您可以将它用于任何进程,而不仅仅是跟踪日志文件。每当我想给一些东西上色时,我通常只是快速地创建一个新的正则表达式。出于这个原因,我更喜欢colout而不是任何自定义日志文件着色工具,因为我只需要学习一种工具,不管我在为什么着色:日志记录、测试输出、在终端中突出显示代码片段的语法等等。

它还避免了在日志文件本身中实际转储ANSI代码,恕我说这是一个坏主意,因为它会破坏日志文件中的grepping模式之类的事情,除非您始终记得在grep正则表达式中匹配ANSI代码。

你可以导入colorlog模块,并使用它的ColoredFormatter为日志消息着色。

例子

主模块样板:

import logging
import os
import sys
try:
import colorlog
except ImportError:
pass


def setup_logging():
root = logging.getLogger()
root.setLevel(logging.DEBUG)
format      = '%(asctime)s - %(levelname)-8s - %(message)s'
date_format = '%Y-%m-%d %H:%M:%S'
if 'colorlog' in sys.modules and os.isatty(2):
cformat = '%(log_color)s' + format
f = colorlog.ColoredFormatter(cformat, date_format,
log_colors = { 'DEBUG'   : 'reset',       'INFO' : 'reset',
'WARNING' : 'bold_yellow', 'ERROR': 'bold_red',
'CRITICAL': 'bold_red' })
else:
f = logging.Formatter(format, date_format)
ch = logging.StreamHandler()
ch.setFormatter(f)
root.addHandler(ch)


setup_logging()
log = logging.getLogger(__name__)

该代码仅在安装了colorlog模块并且输出实际发送到终端时才启用日志消息中的颜色。这可以避免在日志输出重定向时将转义序列写入文件。

此外,还设置了一个自定义配色方案,更适合具有深色背景的终端。

一些日志调用示例:

log.debug   ('Hello Debug')
log.info    ('Hello Info')
log.warn    ('Hello Warn')
log.error   ('Hello Error')
log.critical('Hello Critical')

输出:

enter image description here

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)

使用

Logger("File Name").info("This shows green text")

另一个解决方案,用ZetaSyanthis的颜色:

def config_log(log_level):


def set_color(level, code):
level_fmt = "\033[1;" + str(code) + "m%s\033[1;0m"
logging.addLevelName( level, level_fmt % logging.getLevelName(level) )


std_stream = sys.stdout
isatty = getattr(std_stream, 'isatty', None)
if isatty and isatty():
levels = [logging.DEBUG, logging.CRITICAL, logging.WARNING, logging.ERROR]
for idx, level in enumerate(levels):
set_color(level, 30 + idx )
set_color(logging.DEBUG, 0)
logging.basicConfig(stream=std_stream, level=log_level)

__main__函数中调用它一次。我这里有这样的东西:

options, arguments = p.parse_args()
log_level = logging.DEBUG if options.verbose else logging.WARNING
config_log(log_level)

它还验证输出是否为控制台,否则不使用颜色。

好吧,我想我应该加上我的彩色记录器的变化。

这没什么特别的,但是使用起来非常简单,并且不会更改记录对象,因此如果使用文件处理程序,就可以避免将ANSI转义序列记录到日志文件中。不影响日志信息的格式化。

如果你已经在使用日志模块的格式化程序,你所要做的就是用ColoredFormatter替换你的忠告处理程序Formatter来获得有颜色的级别名称。如果你正在记录整个应用程序,你只需要为顶级记录器这样做。

colored_log.py

#!/usr/bin/env python


from copy import copy
from logging import Formatter


MAPPING = {
'DEBUG'   : 37, # white
'INFO'    : 36, # cyan
'WARNING' : 33, # yellow
'ERROR'   : 31, # red
'CRITICAL': 41, # white on red bg
}


PREFIX = '\033['
SUFFIX = '\033[0m'


class ColoredFormatter(Formatter):


def __init__(self, patern):
Formatter.__init__(self, patern)


def format(self, record):
colored_record = copy(record)
levelname = colored_record.levelname
seq = MAPPING.get(levelname, 37) # default white
colored_levelname = ('{0}{1}m{2}{3}') \
.format(PREFIX, seq, levelname, SUFFIX)
colored_record.levelname = colored_levelname
return Formatter.format(self, colored_record)

示例使用

app.py

#!/usr/bin/env python


import logging
from colored_log import ColoredFormatter


# Create top level logger
log = logging.getLogger("main")


# Add console handler using our custom ColoredFormatter
ch = logging.StreamHandler()
ch.setLevel(logging.DEBUG)
cf = ColoredFormatter("[%(name)s][%(levelname)s]  %(message)s (%(filename)s:%(lineno)d)")
ch.setFormatter(cf)
log.addHandler(ch)


# Add file handler
fh = logging.FileHandler('app.log')
fh.setLevel(logging.DEBUG)
ff = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
fh.setFormatter(ff)
log.addHandler(fh)


# Set log level
log.setLevel(logging.DEBUG)


# Log some stuff
log.debug("app has started")
log.info("Logging to 'app.log' in the script dir")
log.warning("This is my last warning, take heed")
log.error("This is an error")
log.critical("He's dead, Jim")


# Import a sub-module
import sub_module

sub_module.py

#!/usr/bin/env python


import logging
log = logging.getLogger('main.sub_module')


log.debug("Hello from the sub module")

结果

终端输出

终端输出

app.log内容

2017-09-29 00:32:23,434 - main - DEBUG - app has started
2017-09-29 00:32:23,434 - main - INFO - Logging to 'app.log' in the script dir
2017-09-29 00:32:23,435 - main - WARNING - This is my last warning, take heed
2017-09-29 00:32:23,435 - main - ERROR - This is an error
2017-09-29 00:32:23,435 - main - CRITICAL - He's dead, Jim
2017-09-29 00:32:23,435 - main.sub_module - DEBUG - Hello from the sub module

当然,您可以随心所欲地设置终端和日志文件输出的格式。只有日志级别将被着色。

我希望有人发现这是有用的,而不是只是太多的相同。:)

Python示例文件可以从这个GitHub下载。 https://gist.github.com/KurtJacobson/48e750701acec40c7161b5a2f79e6bfd < / p >

有很多回复。但没有人谈论装修师。这是我的。

因为它要简单得多。

不需要导入任何东西,也不需要编写任何子类:

#!/usr/bin/env python
# -*- coding: utf-8 -*-




import logging




NO_COLOR = "\33[m"
RED, GREEN, ORANGE, BLUE, PURPLE, LBLUE, GREY = \
map("\33[%dm".__mod__, range(31, 38))


logging.basicConfig(format="%(message)s", level=logging.DEBUG)
logger = logging.getLogger(__name__)


# the decorator to apply on the logger methods info, warn, ...
def add_color(logger_method, color):
def wrapper(message, *args, **kwargs):
return logger_method(
# the coloring is applied here.
color+message+NO_COLOR,
*args, **kwargs
)
return wrapper


for level, color in zip((
"info", "warn", "error", "debug"), (
GREEN, ORANGE, RED, BLUE
)):
setattr(logger, level, add_color(getattr(logger, level), color))


# this is displayed in red.
logger.error("Launching %s." % __file__)

这将错误设置为红色,调试消息设置为蓝色,等等。就像问题中问的那样。

我们甚至可以使包装器接受color参数来使用logger.debug("message", color=GREY)动态设置消息的颜色

< p >编辑: 这里是在运行时设置颜色的经过调整的装饰器:

def add_color(logger_method, _color):
def wrapper(message, *args, **kwargs):
color = kwargs.pop("color", _color)
if isinstance(color, int):
color = "\33[%dm" % color
return logger_method(
# the coloring is applied here.
color+message+NO_COLOR,
*args, **kwargs
)
return wrapper


# blah blah, apply the decorator...


# this is displayed in red.
logger.error("Launching %s." % __file__)
# this is displayed in blue
logger.error("Launching %s." % __file__, color=34)
# and this, in grey
logger.error("Launching %s." % __file__, color=GREY)

这是一个包含颜色代码的Enum:

class TerminalColour:
"""
Terminal colour formatting codes
"""
# https://stackoverflow.com/questions/287871/print-in-terminal-with-colors
MAGENTA = '\033[95m'
BLUE = '\033[94m'
GREEN = '\033[92m'
YELLOW = '\033[93m'
RED = '\033[91m'
GREY = '\033[0m'  # normal
WHITE = '\033[1m'  # bright white
UNDERLINE = '\033[4m'

这可以应用于每个日志级别的的名字注意这是一个可怕的黑客

logging.addLevelName(logging.INFO, "{}{}{}".format(TerminalColour.WHITE, logging.getLevelName(logging.INFO), TerminalColour.GREY))
logging.addLevelName(logging.WARNING, "{}{}{}".format(TerminalColour.YELLOW, logging.getLevelName(logging.WARNING), TerminalColour.GREY))
logging.addLevelName(logging.ERROR, "{}{}{}".format(TerminalColour.RED, logging.getLevelName(logging.ERROR), TerminalColour.GREY))
logging.addLevelName(logging.CRITICAL, "{}{}{}".format(TerminalColour.MAGENTA, logging.getLevelName(logging.CRITICAL), .GREY))

注意,您的日志格式化程序必须包含日志级别的名称

%(levelname)

例如:

    LOGGING = {
...
'verbose': {
'format': '%(asctime)s %(levelname)s %(name)s:%(lineno)s %(module)s %(process)d %(thread)d %(message)s'
},
'simple': {
'format': '[%(asctime)s] %(levelname)s %(name)s %(message)s'
},

Python 3解决方案,不需要额外的包

定义一个类

import logging


class CustomFormatter(logging.Formatter):


grey = "\x1b[38;20m"
yellow = "\x1b[33;20m"
red = "\x1b[31;20m"
bold_red = "\x1b[31;1m"
reset = "\x1b[0m"
format = "%(asctime)s - %(name)s - %(levelname)s - %(message)s (%(filename)s:%(lineno)d)"


FORMATS = {
logging.DEBUG: grey + format + reset,
logging.INFO: grey + format + reset,
logging.WARNING: yellow + format + reset,
logging.ERROR: red + format + reset,
logging.CRITICAL: bold_red + format + reset
}


def format(self, record):
log_fmt = self.FORMATS.get(record.levelno)
formatter = logging.Formatter(log_fmt)
return formatter.format(record)

实例化记录器

# create logger with 'spam_application'
logger = logging.getLogger("My_app")
logger.setLevel(logging.DEBUG)


# create console handler with a higher log level
ch = logging.StreamHandler()
ch.setLevel(logging.DEBUG)


ch.setFormatter(CustomFormatter())


logger.addHandler(ch)

和使用!

logger.debug("debug message")
logger.info("info message")
logger.warning("warning message")
logger.error("error message")
logger.critical("critical message")

< >强结果 enter image description here < / p >

全配色方案 enter image description here < / p >

对于windows

该解决方案适用于Mac OS、IDE终端。看起来Windows命令提示符在默认情况下根本没有颜色。下面是关于如何启用它们的说明,我还没有尝试https://www.howtogeek.com/322432/how-to-customize-your-command-prompts-color-scheme-with-microsofts-colortool/

FriendlyLog是另一种选择。它适用于Python 2 &3在Linux, Windows和MacOS下。

下面的解决方案只适用于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),然后使用这些属性(仅)在需要的位置获取彩色文本。

(我最近发现的一个方便的技巧:我有一个彩色调试日志文件,每当我想临时增加我的应用程序的日志级别时,我只是tail -f日志文件在不同的终端,并在屏幕上看到调试日志w/o改变任何配置和重新启动应用程序)

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

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

注意:我使用了彩色光,但你可以修改它,使它不再是必需的。此外,对于我的测试,我只是运行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")

输出:

output

除了按级别着色之外,还可以用交替的颜色突出显示日志消息参数吗?我最近为此写了一些简单的代码。另一个优点是使用Python 3大括号格式进行日志调用。("{}")。

查看最新的代码和示例:https://github.com/davidohana/colargulog

日志示例代码:

root_logger = logging.getLogger()
console_handler = logging.StreamHandler(stream=sys.stdout)
console_format = "%(asctime)s - %(levelname)-8s - %(name)-25s - %(message)s"
colored_formatter = ColorizedArgsFormatter(console_format)
console_handler.setFormatter(colored_formatter)
root_logger.addHandler(console_handler)


logger = logging.getLogger(__name__)
logger.info("Hello World")
logger.info("Request from {} handled in {:.3f} ms", socket.gethostname(), 11)
logger.info("Request from {} handled in {:.3f} ms", "127.0.0.1", 33.1)
logger.info("My favorite drinks are {}, {}, {}, {}", "milk", "wine", "tea", "beer")
logger.debug("this is a {} message", logging.getLevelName(logging.DEBUG))
logger.info("this is a {} message", logging.getLevelName(logging.INFO))
logger.warning("this is a {} message", logging.getLevelName(logging.WARNING))
logger.error("this is a {} message", logging.getLevelName(logging.ERROR))
logger.critical("this is a {} message", logging.getLevelName(logging.CRITICAL))
logger.info("Does old-style formatting also work? %s it is, but no colors (yet)", True)

输出:

enter image description here

实现:

"""
colargulog - Python3 Logging with Colored Arguments and new string formatting style


Written by david.ohana@ibm.com
License: Apache-2.0
"""


import logging
import logging.handlers
import re




class ColorCodes:
grey = "\x1b[38;21m"
green = "\x1b[1;32m"
yellow = "\x1b[33;21m"
red = "\x1b[31;21m"
bold_red = "\x1b[31;1m"
blue = "\x1b[1;34m"
light_blue = "\x1b[1;36m"
purple = "\x1b[1;35m"
reset = "\x1b[0m"




class ColorizedArgsFormatter(logging.Formatter):
arg_colors = [ColorCodes.purple, ColorCodes.light_blue]
level_fields = ["levelname", "levelno"]
level_to_color = {
logging.DEBUG: ColorCodes.grey,
logging.INFO: ColorCodes.green,
logging.WARNING: ColorCodes.yellow,
logging.ERROR: ColorCodes.red,
logging.CRITICAL: ColorCodes.bold_red,
}


def __init__(self, fmt: str):
super().__init__()
self.level_to_formatter = {}


def add_color_format(level: int):
color = ColorizedArgsFormatter.level_to_color[level]
_format = fmt
for fld in ColorizedArgsFormatter.level_fields:
search = "(%\(" + fld + "\).*?s)"
_format = re.sub(search, f"{color}\\1{ColorCodes.reset}", _format)
formatter = logging.Formatter(_format)
self.level_to_formatter[level] = formatter


add_color_format(logging.DEBUG)
add_color_format(logging.INFO)
add_color_format(logging.WARNING)
add_color_format(logging.ERROR)
add_color_format(logging.CRITICAL)


@staticmethod
def rewrite_record(record: logging.LogRecord):
if not BraceFormatStyleFormatter.is_brace_format_style(record):
return


msg = record.msg
msg = msg.replace("{", "_\{\{")
msg = msg.replace("}", "_}}")
placeholder_count = 0
# add ANSI escape code for next alternating color before each formatting parameter
# and reset color after it.
while True:
if "_\{\{" not in msg:
break
color_index = placeholder_count % len(ColorizedArgsFormatter.arg_colors)
color = ColorizedArgsFormatter.arg_colors[color_index]
msg = msg.replace("_\{\{", color + "{", 1)
msg = msg.replace("_}}", "}" + ColorCodes.reset, 1)
placeholder_count += 1


record.msg = msg.format(*record.args)
record.args = []


def format(self, record):
orig_msg = record.msg
orig_args = record.args
formatter = self.level_to_formatter.get(record.levelno)
self.rewrite_record(record)
formatted = formatter.format(record)


# restore log record to original state for other handlers
record.msg = orig_msg
record.args = orig_args
return formatted




class BraceFormatStyleFormatter(logging.Formatter):
def __init__(self, fmt: str):
super().__init__()
self.formatter = logging.Formatter(fmt)


@staticmethod
def is_brace_format_style(record: logging.LogRecord):
if len(record.args) == 0:
return False


msg = record.msg
if '%' in msg:
return False


count_of_start_param = msg.count("{")
count_of_end_param = msg.count("}")


if count_of_start_param != count_of_end_param:
return False


if count_of_start_param != len(record.args):
return False


return True


@staticmethod
def rewrite_record(record: logging.LogRecord):
if not BraceFormatStyleFormatter.is_brace_format_style(record):
return


record.msg = record.msg.format(*record.args)
record.args = []


def format(self, record):
orig_msg = record.msg
orig_args = record.args
self.rewrite_record(record)
formatted = self.formatter.format(record)


# restore log record to original state for other handlers
record.msg = orig_msg
record.args = orig_args
return formatted

一个方便的带有tput颜色的bash脚本

# Simple using tput
bold=$(tput bold)
reset=$(tput sgr0)


fblack=$(tput setaf 0)
fred=$(tput setaf 1)
fgreen=$(tput setaf 2)
fyellow=$(tput setaf 3)
fblue=$(tput setaf 4)
fmagenta=$(tput setaf 5)
fcyan=$(tput setaf 6)
fwhite=$(tput setaf 7)
fnotused=$(tput setaf 8)
freset=$(tput setaf 9)


bblack=$(tput setab 0)
bred=$(tput setab 1)
bgreen=$(tput setab 2)
byellow=$(tput setab 3)
bblue=$(tput setab 4)
bmagenta=$(tput setab 5)
bcyan=$(tput setab 6)
bwhite=$(tput setab 7)
bnotused=$(tput setab 8)
breset=$(tput setab 9)


# 0 - Emergency (emerg)       $fred       # something is wrong... go red
# 1 - Alerts (alert)          $fred       # something is wrong... go red
# 2 - Critical (crit)         $fred       # something is wrong... go red
# 3 - Errors (err)            $fred       # something is wrong... go red
# 4 - Warnings (warn)         $fyellow    # yellow yellow dirty logs
# 5 - Notification (notice)   $fwhite     # common stuff
# 6 - Information (info)      $fblue      # sky is blue
# 7 - Debug (debug)           $fgreen     # lot of stuff to read... go green

安装colorlog包,你可以立即在你的日志消息中使用颜色:

  • 获取一个logger实例,就像你通常做的那样。
  • 设置日志级别。你也可以使用像DEBUG这样的常量 和INFO直接从日志模块
  • 将消息格式化程序设置为所提供的ColoredFormatter
import colorlog


logger = colorlog.getLogger()
logger.setLevel(colorlog.colorlog.logging.DEBUG)


handler = colorlog.StreamHandler()
handler.setFormatter(colorlog.ColoredFormatter())
logger.addHandler(handler)


logger.debug("Debug message")
logger.info("Information message")
logger.warning("Warning message")
logger.error("Error message")
logger.critical("Critical message")
< p >输出: enter image description here < / p >

更新:额外信息

只需更新ColoredFormatter:

handler.setFormatter(colorlog.ColoredFormatter('%(log_color)s [%(asctime)s] %(levelname)s [%(filename)s.%(funcName)s:%(lineno)d] %(message)s', datefmt='%a, %d %b %Y %H:%M:%S'))
< p >输出: enter image description here < / p >

包:

pip install colorlog

输出:

Collecting colorlog
Downloading colorlog-4.6.2-py2.py3-none-any.whl (10.0 kB)
Installing collected packages: colorlog
Successfully installed colorlog-4.6.2

Emoji

你可以像其他人在回答中提到的那样,为文本使用颜色,使文本具有丰富的背景色或前景色。

但是你可以用emojis代替!例如,你可以用⚠️表示警告消息,用🛑表示错误消息。

或者简单地用这些笔记本作为一种颜色:

print("📕: error message")
print("📙: warning message")
print("📗: ok status message")
print("📘: action message")
print("📓: canceled status message")
print("📔: Or anything you like and want to recognize immediately by color")

🎁奖金:

此方法还可以帮助您快速扫描和查找日志直接在源代码中


如何打开表情符号选择器?

__abc0 __abc1 + __abc2 + __abc3

__abc0 __abc1 + __abc2

linux <强> < / >强: 控制 + 控制 +

coloredlogs

Instalation

pip install coloredlogs

使用

最小的用法:
import logging
import coloredlogs


coloredlogs.install()  # install a handler on the root logger


logging.debug('message with level debug')
logging.info('message with level info')
logging.warning('message with level warning')
logging.error('message with level error')
logging.critical('message with level critical')
< p >的结果: minimal usage < / p >
从消息级调试开始:
import logging
import coloredlogs


coloredlogs.install(level='DEBUG')  # install a handler on the root logger with level debug


logging.debug('message with level debug')
logging.info('message with level info')
logging.warning('message with level warning')
logging.error('message with level error')
logging.critical('message with level critical')
< p >的结果: debug level < / p >
从库中隐藏消息:
import logging
import coloredlogs


logger = logging.getLogger(__name__)  # get a specific logger object
coloredlogs.install(level='DEBUG')  # install a handler on the root logger with level debug
coloredlogs.install(level='DEBUG', logger=logger)  # pass a specific logger object


logging.debug('message with level debug')
logging.info('message with level info')
logging.warning('message with level warning')
logging.error('message with level error')
logging.critical('message with level critical')
< p >的结果: debug level < / p >
格式化日志消息:
import logging
import coloredlogs


logger = logging.getLogger(__name__)  # get a specific logger object
coloredlogs.install(level='DEBUG')  # install a handler on the root logger with level debug
coloredlogs.install(level='DEBUG', logger=logger)  # pass a specific logger object
coloredlogs.install(
level='DEBUG', logger=logger,
fmt='%(asctime)s.%(msecs)03d %(filename)s:%(lineno)d %(levelname)s %(message)s'
)


logging.debug('message with level debug')
logging.info('message with level info')
logging.warning('message with level warning')
logging.error('message with level error')
logging.critical('message with level critical')
< p >的结果: format log messages < / p >
可用的格式属性:
  • %(asctime)s -时间作为人类可读的字符串,当日志调用发出
  • %(created)f -当日志调用发出时,时间为浮动
  • %(filename)s -文件名
  • %(funcName)s -包含日志调用的函数名
  • %(hostname)s -系统主机名
  • %(levelname)s -文本日志级别
  • %(levelno)s -整数日志级别
  • %(lineno)d -发出日志调用的行号
  • %(message)s -传递给日志调用的消息(与%(msg)s相同)
  • %(module)s -发出日志调用的不带扩展名的文件名
  • %(msecs)d -发出日志调用的毫秒部分时间
  • %(msg)s -传递给日志调用的消息(与%(message)s相同)
  • %(name)s记录器名称
  • %(pathname)s -包含日志调用的文件的完整路径名
  • %(process)d进程ID
  • %(processName)s进程名
  • %(programname)s系统程序名
  • %(relativeCreated)d -日志调用发出时的时间,单位为毫秒,相对于日志模块加载时的时间
  • 线程ID
  • %(threadName)s线程名
  • %(username)s -系统用户名

来源:

Coloredlogs package

日志库 .

使用丰富的库

< >强富强< / >提供了一个日志处理程序,它将对Python日志模块编写的文本进行格式化和着色。

它很容易使用和可定制+工作在cmd.exe, Windows终端ConEmu和Jupyter笔记本!(我尝试了很多包,我告诉你,只有丰富的的颜色在笔记本上工作。)

< >强富强< / >还带有许多其他奇特的功能。

安装

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

终端截图

最简单的解决方案可能是彩色光。

在你的电脑上安装Colorama:

pip install colorama

然后把它添加到你的Python程序中:

import colorama
print(Fore.GREEN + "test123")

如果你需要多颜色的东西,使用YAChalk

在你的电脑上安装YAChalk:

pip install yachalk

将它添加到你的Python程序中:

from yachalk import chalk
print(chalk.blue("This is blue and {chalk.red("this is red")})

使用标准Python3日志库的解决方案

我很高兴能分享这个灵活的日志着色解决方案。我认为这是一个改进的解决方案由@SergeyPleshakov。我利用日志记录的额外kwargs来设置日志前缀和后缀。然后,我们只需默认前缀和后缀,以与日志级别对应的终端颜色代码开始和结束。

奖金功能✨🍰✨

额外的prefixsuffix可以被日志调用重写为任何值。您希望调试日志以🐛作为前缀,为什么不呢?您希望其中一个信息日志是绿色的,而不是默认的,去做吧!

定义终端ColorColorLogFormatter

import logging




class Color:
"""A class for terminal color codes."""


BOLD = "\033[1m"
BLUE = "\033[94m"
WHITE = "\033[97m"
GREEN = "\033[92m"
YELLOW = "\033[93m"
RED = "\033[91m"
BOLD_WHITE = BOLD + WHITE
BOLD_BLUE = BOLD + BLUE
BOLD_GREEN = BOLD + GREEN
BOLD_YELLOW = BOLD + YELLOW
BOLD_RED = BOLD + RED
END = "\033[0m"




class ColorLogFormatter(logging.Formatter):
"""A class for formatting colored logs."""


FORMAT = "%(prefix)s%(msg)s%(suffix)s"


LOG_LEVEL_COLOR = {
"DEBUG": {'prefix': '', 'suffix': ''},
"INFO": {'prefix': '', 'suffix': ''},
"WARNING": {'prefix': Color.BOLD_YELLOW, 'suffix': Color.END},
"ERROR": {'prefix': Color.BOLD_RED, 'suffix': Color.END},
"CRITICAL": {'prefix': Color.BOLD_RED, 'suffix': Color.END},
}


def format(self, record):
"""Format log records with a default prefix and suffix to terminal color codes that corresponds to the log level name."""
if not hasattr(record, 'prefix'):
record.prefix = self.LOG_LEVEL_COLOR.get(record.levelname.upper()).get('prefix')
        

if not hasattr(record, 'suffix'):
record.suffix = self.LOG_LEVEL_COLOR.get(record.levelname.upper()).get('suffix')


formatter = logging.Formatter(self.FORMAT)
return formatter.format(record)

实例化记录器

logger = logging.getLogger('bobcat')
logger.setLevel('DEBUG')


stream_handler = logging.StreamHandler()
stream_handler.setFormatter(ColorLogFormatter())
logger.addHandler(stream_handler)

和使用!

    logger.debug("This is debug", extra={'prefix': '🐛 '})
logger.info("This is info")
logger.info("This is a green info", extra={'prefix': Color.GREEN, 'suffix': Color.END})
logger.warning("This is warning")
logger.error("This is error")
logger.critical("This is critical")

瞧!

截图

这是@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]
)

给任何有同样需要的人,我推荐我自己的包TCPrint。 它基于彩色光(提供跨平台兼容性),但不同于它使用熟悉的<tags>标记文本颜色,并包含日志标记

安装:

pip install ctprint

颜色:

from ctprint inport ctp, ctdecode, cterr, ctlog


# print colored text
ctp('<bw> black text on white background /> default formating')

错误处理:

# print error message
try:
1/0  # any broken line
except Exception as _ex:
cterr(_ex)

变量记录:

var0 = var1 = 0


# print varName-varValue pairs
def example_ctlog():


var2 = 'string val'
var3 = {'ctp_string': '<bg_red><red>red text on red background (NO) >'}


# out of the function, var0=var2 - nothing problems.
ctlog(var0=var0, var1=var1, var2=var2, var3=var3)

和更多的:

ctp.help() # print help dialog with all supported tags and functions

除了日志功能和颜色标记,还有<error><log>快速标记用于标记用户输出

如果你需要加速日志记录和提高终端(vscode/pycharm/cmd/bash等)的可读性,而不是定制🌈或🦄风格的命令行界面,你知道该怎么做。CTPrint 是为第一个发明的吗

好运吧!

简化的日志库:

class handler(logging.StreamHandler):
colors = {
logging.DEBUG: '\033[37m',
logging.INFO: '\033[36m',
logging.WARNING: '\033[33m',
logging.ERROR: '\033[31m',
logging.CRITICAL: '\033[101m',
}
reset = '\033[0m'
fmtr = logging.Formatter('%(levelname)s %(message)s')


def format(self, record):
color = self.colors[record.levelno]
log = self.fmtr.format(record)
reset = self.reset
return color + log + reset




logging.basicConfig(level=logging.DEBUG, handlers=[handler()])

使用龙卷风库

< >强龙卷风< / >强 web框架提供了一些实用程序,包括tornado.log.LogFormatter格式化器,它可以在没有框架其他部分的情况下使用。

对不支持ANSI颜色代码的Windows版本的颜色支持是通过使用彩色光库启用的。希望使用它的应用程序必须首先调用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")

我更喜欢使用这个片段:

import logging
from enum import Enum


CSI = '\033['


Color = Enum(
'Color', 'BLACK RED GREEN YELLOW BLUE MAGENTA CYAN WHITE', start=30
)




class AnsiColorHandler(logging.StreamHandler):
LOGLEVEL_COLORS = {
'DEBUG': Color.BLUE,
'INFO': Color.GREEN,
'WARNING': Color.RED,
'ERROR': Color.RED,
'CRITICAL': Color.RED,
}


def __init__(self) -> None:
super().__init__()
self.formatter = logging.Formatter("%(levelname)-8s - %(message)s")


def format(self, record: logging.LogRecord) -> str:
message: str = super().format(record)
# use colors in tty
if self.stream.isatty() and (
color := self.LOGLEVEL_COLORS.get(record.levelname)
):
message = f'{CSI}{color.value}m{message}{CSI}0m'
return message




# setup logger
# logger = logging.getLogger(__package__)
logger = logging.getLogger(__name__)
logger.addHandler(AnsiColorHandler())

用法:

import logging


from .log import logger


logger.setLevel(logging.DEBUG)
logger.debug("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa")

只要你不想去发明轮子。

只需pip install loguru,然后:

from loguru import logger


if __name__ == '__main__':
message = "Message text"


logger.info(message)
logger.debug(message)
logger.warning(message)
logger.success(message)
logger.error(message)
logger.critical(message)
< p >输出: enter image description here < / p >

您可以更改格式,颜色,写入文件从盒子…这里是文档