前段时间,我看到一个带有彩色输出的 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 = "\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 重置为以前的值(注释中的 Michael )。
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")
https://i.stack.imgur.com/klCcc.png
https://i.stack.imgur.com/iZU5S.png
对于窗户
此解决方案适用于 Mac OS、IDE 终端。默认情况下,Windows 命令提示符似乎根本没有颜色。以下是有关如何启用它们的说明,我没有尝试过https://www.howtogeek.com/322432/how-to-customize-your-command-prompts-color-scheme-with-microsofts-colortool/
←[38;21m2019-11-12 19:29:50,994 - My_app - DEBUG - debug message (test_colored_log.py:43)←[0m ←[38;21m2019-11-12 19:29:50,994 - My_app - INFO - info message (test_colored_log.py:44)←[0m ←[33;21m2019-11-12 19:29:50,994 - My_app - WARNING - warning message (test_colored_log.py:45)←[0m ←[31;21m2019-11-12 19:29:50,994 - My_app - ERROR - error message (test_colored_log.py:46)←[0m ←[31;1m2019-11-12 19:29:50,994 - My_app - CRITICAL - critical message (test_colored_log.py:47)←[0m
...21m
更改为 20m
似乎在我的工作中很完美。以防万一有人遇到同样的问题。
几年前,我写了一个彩色流处理程序供我自己使用。然后我看到了这个页面,发现了一组人们正在复制/粘贴的代码片段 :-(。我的流处理程序目前仅适用于 UNIX(Linux、Mac OS X),但优点是它是 available on PyPI(和 { 2}) 并且使用起来非常简单。它还具有 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、日志级别和日志消息。这是它在实践中的样子:
https://i.stack.imgur.com/AgqpA.png
注意:使用带有 MinTTY 的 Git Bash 时
Windows 上的 Git Bash 有一些记录在案的怪癖:Winpty and Git Bash
对于 ANSI 转义码和 ncurses 样式的字符重写和动画,您需要在命令前加上 winpty
。
$ winpty coloredlogs --demo
$ winpty python your_colored_logs_script.py
coloredlogs.install()
时不断收到 AttributeError: 'module' object has no attribute 'install'
。你能用最新版本确认一下吗?
更新:因为这是我长久以来一直想从头开始的痒,所以我继续为像我这样只想用简单方法做事的懒人编写了一个库:zenlog
Colorlog 非常适合这一点。它是 available on PyPI(因此可以通过 pip install colorlog
安装)并且是 actively maintained。
这是一个快速复制和粘贴的片段,用于设置日志记录和打印看起来不错的日志消息:
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")
输出:
https://github.com/ManufacturaInd/python-zenlog/raw/master/colorlogs.png
setLevel
的三个调用吗?)
预定义日志级别的快速而肮脏的解决方案,无需定义新类。
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))
logging.basicConfig(format='%(asctime)s [%(name)s] [%(levelname)s] %(message)s')
当然,%(levelnames)s
很重要。
echo -e "Normal texst \033[1;31mred bold text\033[0m normal text again"
。 echo -e
选项将 "\033" 解释为 Escape ASCII 符号的八进制形式。这个特殊符号使一些兼容的终端将后续字符(包括 char m
)解释为特殊命令。 en.wikipedia.org/wiki/ANSI_escape_code
if sys.sdterr.isatty():
中。在这种情况下,如果您将输出重定向到文件,则文件将不包含这些转义字符。
这是一个适用于任何平台的解决方案。如果它不只是告诉我,我会更新它。
工作原理:在支持 ANSI 转义的平台上使用它们(非 Windows),在 Windows 上它确实使用 API 调用来更改控制台颜色。
该脚本确实破解了标准库中的 logging.StreamHandler.emit 方法,为其添加了一个包装器。
测试着色器.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")
着色器.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())
args[1].msg = color + str(args[1].msg) + '\x1b[0m' # normal
。
TestColorer.py
中的那一点让我很担心。
好吧,我想我不妨添加我的彩色记录器的变体。
这没什么花哨的,但使用起来非常简单,并且不会更改记录对象,因此如果使用文件处理程序,则可以避免将 ANSI 转义序列记录到日志文件中。它不影响日志消息格式。
如果您已经在使用 logging module's Formatter,那么您只需将您的顾问处理程序 Formatter 替换为 ColoredFormatter 即可获得彩色级别名称。如果您正在记录整个应用程序,您只需为顶级记录器执行此操作。
彩色日志.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)
示例用法
应用程序.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
子模块.py
#!/usr/bin/env python
import logging
log = logging.getLogger('main.sub_module')
log.debug("Hello from the sub module")
结果
终端输出
https://i.stack.imgur.com/OsmlG.png
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
当然,您可以根据需要对终端和日志文件输出进行格式化。只有日志级别会被着色。
我希望有人觉得这很有用,而且它不仅仅是太多相同的东西。 :)
可从此 GitHub Gist 下载 Python 示例文件:https://gist.github.com/KurtJacobson/48e750701acec40c7161b5a2f79e6bfd
return
之前添加这一行:colored_record.msg = ('{0}{1}m{2}{3}').format(self.PREFIX, seq, colored_record.getMessage(), self.SUFFIX)
print()
语句丰富多彩?
您可以导入 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')
输出:
https://i.stack.imgur.com/lWWpI.png
colorlog.basicConfig
而不是 logging.basicConfig
,它有一些很好的默认值
我更新了 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
super
的评论仅适用于我猜的一些古老的 Python 版本?因为这个答案是从 2010 年开始的。它使用 Python 2.7 对我来说效果很好
我修改了 Sorin 提供的 original example 并将 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)
看看下面的解决方案。流处理程序应该是进行着色的东西,然后您可以选择为单词着色,而不仅仅是整行(使用格式化程序)。
http://plumberjack.blogspot.com/2010/12/colorizing-logging-output-in-terminals.html
现在有一个发布的 PyPi 模块,用于可定制的彩色日志输出:
https://pypi.python.org/pypi/rainbow_logging_handler/
和
https://github.com/laysakura/rainbow_logging_handler
支持视窗
支持 Django
可定制的颜色
由于这是作为 Python Egg 分发的,因此对于任何 Python 应用程序都非常容易安装。
除了按级别着色之外,突出显示还使用交替颜色记录消息参数怎么样?我最近为此编写了简单的代码。另一个优点是日志调用是使用 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)
输出:
https://i.stack.imgur.com/0Or6e.png
执行:
"""
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
安装 colorlog 包,您可以立即在日志消息中使用颜色:
获取一个记录器实例,就像你通常做的那样。
设置日志记录级别。您还可以直接使用来自日志记录模块的 DEBUG 和 INFO 等常量。
将消息格式化程序设置为 colorlog 库提供的 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")
https://i.stack.imgur.com/sXE9G.png
更新:额外信息
只需更新 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'))
https://i.stack.imgur.com/UMeCl.png
包裹:
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
为任何终端文本着色的简单但非常灵活的工具是“colout”。
pip install colout
myprocess | colout REGEX_WITH_GROUPS color1,color2...
与正则表达式的第 1 组匹配的“myprocess”输出中的任何文本将用 color1 着色,第 2 组用 color2 着色,等等。
例如:
tail -f /var/log/mylogfile | colout '^(\w+ \d+ [\d:]+)|(\w+\.py:\d+ .+\(\)): (.+)$' white,black,cyan bold,bold,normal
即第一个正则表达式组(parens)匹配日志文件中的初始日期,第二组匹配python文件名、行号和函数名,第三组匹配之后出现的日志消息。我还使用“粗体/法线”的并行序列以及颜色序列。这看起来像:
https://i.stack.imgur.com/99ztB.png
请注意,与我的任何正则表达式不匹配的行或部分行仍会被回显,因此这不像 'grep --color' - 没有任何内容从输出中过滤出来。
显然,这足够灵活,您可以在任何进程中使用它,而不仅仅是尾随日志文件。每当我想给某些东西上色时,我通常都会在运行中创建一个新的正则表达式。出于这个原因,与任何自定义日志文件着色工具相比,我更喜欢 colout,因为我只需要学习一个工具,无论我在着色什么:日志记录、测试输出、在终端中突出显示代码片段的语法等。
它还避免了在日志文件本身中实际转储 ANSI 代码,恕我直言,这是一个坏主意,因为它会破坏诸如在日志文件中查找模式之类的事情,除非您始终记得在 grep 正则表达式中匹配 ANSI 代码。
有很多回应。但是没有人在谈论装饰器。所以这是我的。
因为它要简单得多。
无需导入任何内容,也无需编写任何子类:
#!/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)
动态设置消息的颜色
编辑:所以这是在运行时设置颜色的改编装饰器:
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)
使用丰富的库
Rich 提供了一个 logging handler,它将格式化和着色由 Python 的日志记录模块编写的文本。
它易于使用且可自定义 + 适用于 cmd.exe、Windows Terminal、ConEmu 和 Jupyter Notebook! (我试过很多我告诉你的包,只有 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...")
https://i.stack.imgur.com/rn3ZO.png
python -m rich.logging
即可查看不同用例的示例 :-)
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)
彩色原木
安装
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')
https://i.stack.imgur.com/A1axw.png
从消息级调试开始:
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')
https://i.stack.imgur.com/S3AAi.png
隐藏库中的消息:
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')
https://i.stack.imgur.com/S3AAi.png
格式化日志消息:
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')
https://i.stack.imgur.com/0aBWR.png
可用的格式属性:
%(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 - 发出记录调用时的整数毫秒数,相对于加载记录模块的时间
%(thread)d - 线程 ID
%(threadName)s - 线程名称
%(username)s - 系统用户名
资料来源:
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)))`
[9*m
代码的好例子! PS你的最后一行让我有点担心,因为它还不知道whether logging outside of a function definition is safe in Python。
使用标准 Python3 日志库的解决方案
我很高兴能分享这个灵活的日志着色解决方案。我认为这是@SergeyPleshakov 对这个solution 的改进。我利用日志记录的 extra kwargs 设置日志前缀和后缀。然后我们只是默认前缀和后缀以与日志级别对应的终端颜色代码开始和结束。
奖励功能✨🍰✨
额外的 prefix
和 suffix
可以被日志调用覆盖为任何内容。您希望调试日志以 🐛 为前缀,为什么不呢。您希望其中一个信息日志为绿色而不是默认值,那就去吧!
定义终端 Color
和 ColorLogFormatter
类
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")
瞧!
https://i.stack.imgur.com/ZQJpg.png
这是我的解决方案:
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])
这是 airmind 示例的另一个 Python3 变体。我想要一些在其他示例中没有看到的特定功能
为终端使用颜色,但不要在文件处理程序中写入不可打印的字符(我为此定义了 2 个格式化程序)
能够覆盖特定日志消息的颜色
从文件配置记录器(在本例中为 yaml)
注意:我使用了 colorama,但您可以修改它,因此它不是必需的。同样对于我的测试,我只是在运行 python 文件,所以我的类在模块 __main__
中,您必须将 (): __main__.ColoredFormatter
更改为您的模块。
pip install colorama pyyaml
日志记录.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]
主文件
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")
输出:
https://i.stack.imgur.com/AsvRt.png
表情符号
您可以像其他人在他们的答案中提到的那样使用文本颜色来获得带有背景或前景色的彩色文本。
但是您可以改用表情符号!例如,您可以将 ⚠️
用于警告消息,将 🛑
用于错误消息。
或者简单地将这些笔记本用作颜色:
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")
🎁 奖励:
此方法还可以帮助您直接在源代码中快速扫描和查找日志。
如何打开表情符号选择器?
mac os: 控制 + 命令 + 空格
windows: win + .
linux: control + . 或 control + ;
我遇到的问题是正确设置格式化程序:
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
虽然其他解决方案看起来不错,但它们存在一些问题。有些会为整条线着色,而有些则不需要,有些则忽略了您可能拥有的任何配置。下面的解决方案只影响消息本身。
代码
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
。
[17:01:36]:WARNING:this should be yellowthis should be yellow
或整行被打印两次?
log_format
中删除 7s:%(message)s
。
我有两个要添加的提交,其中一个仅对消息着色(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
刚刚在类似问题上回答了同样的问题:Python | change text color in shell
我们的想法是使用 clint 库。它支持 MAC、Linux 和 Windows shell (CLI)。
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")
Formatter
并在StreamHandler
上指定它的用途,您的答案就很好。但是不需要记录器子类。事实上,使用记录器类会为每个创建的记录器添加一个处理程序,这不是您通常想要的。ColoredFormatter
的附注。它正在更改记录对象,该对象被进一步传递给其他处理程序或传播到其他记录器。如果您配置了文件记录器等,您可能不希望在日志文件中有颜色。为避免这种情况,最好在操作 levelname 属性之前简单地使用copy.copy()
创建record
的副本,或者在返回格式化字符串之前将 levelname 重置为以前的值。