我怎样才能颜色Python日志输出?
前段时间,我看到一个彩色输出的Mono应用程序,大概是因为它的日志系统(因为所有的消息都是标准化的)。
现在,Python有了logging
模块,可以让你指定很多选项来自定义输出。 所以,我想像一下类似的东西可能与Python,但我不知道如何做到这一点。
有什么办法使Python logging
模块输出的颜色?
我想要的(例如)红色的错误,蓝色或黄色的debugging信息,等等。
当然,这可能需要一个兼容的terminal(大多数现代terminal); 但是如果不支持颜色,我可以回退到原始的logging
输出。
任何想法如何可以得到日志模块的彩色输出?
我已经知道颜色逃脱了,前一阵子我在bash提示中使用了它们。 不pipe怎么说,还是要谢谢你。
我想要的是将其与日志logging模块集成在一起,我经过几次尝试和错误后最终做了这个。
这是我最终的结果:
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)
并使用它,创build您自己的logging器:
# 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)
以防万一谁需要它。
如果您使用多个logging器或处理程序,请注意: ColoredFormatter
正在更改logging对象,该对象将进一步传递给其他处理程序或传播到其他logging器。 如果您configuration了文件logging器等,则可能不希望在日志文件中包含颜色。 为了避免这种情况,最好在操作levelname属性之前用copy.copy()
简单地创build一个record
的副本,或者在返回格式化的string之前,将levelname重置为前一个值。
几年前,我为自己使用写了一个彩色的stream处理程序。 然后我遇到了这个页面,发现了一些代码片断,人们复制/粘贴:-(。我的stream处理程序目前只能在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!
上例中显示的默认日志格式包含date,时间,主机名,logging器的名称,PID,日志级别和日志消息。 这是在实践中看起来像:
这是一个可以在任何平台上工作的解决scheme。 如果它不只是告诉我,我会更新它。
它是如何工作的:在支持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())
快速和肮脏的解决scheme预定义的日志级别,而无需定义一个新的类
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))
更新 :因为这是一个痒痒的问题,所以我一直想要这么做,于是我为一个像我这样的懒惰的人写了一个图书馆,他们只是想要简单的方法来做事情: zenlog
Colorlog对此非常好。 它在PyPI上是可用的 (因此可以通过pip install colorlog
)并且被主动维护 。
这里有一个快速的复制和粘贴片段来设置日志logging和打印体面的日志消息:
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")
输出:
我更新了airmind支持前景和背景标签的例子。 只需在日志格式化程序string中使用颜色variables$ 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
所以,现在你可以简单地在你的configuration文件中执行以下操作:
[formatter_colorFormatter] class=logging.ColorFormatter format= $COLOR%(levelname)s $RESET %(asctime)s $BOLD$COLOR%(name)s$RESET %(message)s
看看下面的解决scheme。 stream处理程序应该是做着色的东西,那么你可以select使用单词而不是整行(使用Formatter)。
http://plumberjack.blogspot.com/2010/12/colorizing-logging-output-in-terminals.html
我将Sorin提供的原始示例和子类StreamHandler修改为ColorizedConsoleHandler。
他们的解决scheme的缺点是它修改消息,因为这是修改实际的logmessage其他任何处理程序也将得到修改后的消息。
由于我们使用了多个logging器,这导致在我们的情况下在他们的颜色代码的日志文件。
下面的类只能在支持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)
您可以导入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模块并且输出实际发送到terminal,代码仅在日志消息中启用颜色。 这可以避免在日志输出redirect时将转义序列写入文件。
此外,还设置了一个自定义的颜色scheme,更适合黑暗背景的terminal。
logging呼叫的一些例子:
log.debug ('Hello Debug') log.info ('Hello Info') log.warn ('Hello Warn') log.error ('Hello Error') log.critical('Hello Critical')
输出:
现在有一个发布的PyPi模块用于可定制的彩色日志logging输出:
https://pypi.python.org/pypi/rainbow_logging_handler/
和
https://github.com/laysakura/rainbow_logging_handler
-
支持Windows
-
支持Django
-
可定制的颜色
由于这是以Python的forms发布的,所以对于任何Python应用程序来说安装都非常容易。
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)
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)))`
一个简单但非常灵活的着色任何terminal文本的工具是“ 大胆 ”。
pip install colout myprocess | colout REGEX_WITH_GROUPS color1,color2...
在“myprocess”输出中与正则expression式的组1匹配的任何文本将使用color1进行着色,组2使用color2进行着色等。
例如:
tail -f /var/log/mylogfile | colout '^(\w+ \d+ [\d:]+)|(\w+\.py:\d+ .+\(\)): (.+)$' white,black,cyan bold,bold,normal
即第一个正则expression式组(parens)匹配日志文件中的起始date,第二组匹配python文件名,行号和函数名称,第三组匹配之后的日志消息。 我也使用“粗体/法线”的平行序列以及颜色序列。 这看起来像:
请注意,与我的任何正则expression式不匹配的行或部分行仍然被回显,所以这不像'grep –color' – 没有任何东西被过滤出输出。
显然,这是非常灵活的,您可以将它用于任何进程,而不仅仅是加载日志文件。 我通常只是在任何时候想要着色一些东西的时候,随时掀起一个新的正则expression式。 出于这个原因,我更喜欢colout到任何自定义的日志文件着色工具,因为我只需要学习一个工具,无论我着色如何:日志logging,testing输出,语法突出显示terminal代码片段等。
它也避免了在日志文件本身中实际转储ANSI代码,恕我直言,这是一个坏主意,因为它会破坏日志文件中模式的格式化,除非你总是记得在你的grep正则expression式中匹配ANSI代码。
这是我的解决scheme:
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])
我遇到的麻烦是正确设置格式化程序:
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
虽然其他解决scheme似乎很好,但他们有一些问题。 有些人会把有时候不需要的整个线条着色,有些则会忽略你可能在一起的任何configuration。 下面的解决scheme不会影响消息本身。
码
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)。 这些还包括比以前的解决scheme更多的ANSI颜色代码。
一些内容已经源于(修改):上面的post,和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
使用pyfancy 。
例:
print(pyfancy.RED + "Hello Red!" + pyfancy.END)
另一个解决scheme,与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)
它也validation输出是控制台,否则不使用颜色。
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")
Well, I guess I might as well add my variation of the colored logger.
This is nothing fancy, but it is very simple to use and does not change the record object, thereby avoids logging the ANSI escape sequences to a log file if a file handler is used. It does not effect the log message formatting.
If you are already using the logging module's Formatter , all you have to do to get colored level names is to replace your counsel handlers Formatter with the ColoredFormatter. If you are logging an entire app you only need to do this for the top level logger.
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")
结果
Terminal output
app.log content
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 - ERROR - Hello from the sub module
Of course you can get as fancy as you want with formatting the terminal and log file outputs. Only the log level will be colorized.
I hope somebody finds this useful and it is not just too much more of the same. 🙂
The Python example files can be downloaded from this GitHub Gist: https://gist.github.com/KurtJacobson/48e750701acec40c7161b5a2f79e6bfd
Just answered the same on similar question: Python | 改变shell中的文本颜色
The idea is to use the clint library. Which has support for MAC, Linux and Windows shells (CLI).