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

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

是否有办法使Python日志模块输出为彩色?

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

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

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


当前回答

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)

使用

日志记录器("文件名").info("显示绿色文本")

其他回答

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

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

如果你已经在使用日志记录模块的Formatter,你所要做的就是用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 Gist下载: https://gist.github.com/KurtJacobson/48e750701acec40c7161b5a2f79e6bfd

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

结果:

从消息级调试开始:

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

结果:

从库中隐藏消息:

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

结果:

格式化日志消息:

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

结果:

可用的格式属性:

%(asctime)s - Time as human-readable string, when logging call was issued %(created)f - Time as float when logging call was issued %(filename)s - File name %(funcName)s - Name of function containing the logging call %(hostname)s - System hostname %(levelname)s - Text logging level %(levelno)s - Integer logging level %(lineno)d - Line number where the logging call was issued %(message)s - Message passed to logging call (same as %(msg)s) %(module)s - File name without extension where the logging call was issued %(msecs)d - Millisecond part of the time when logging call was issued %(msg)s - Message passed to logging call (same as %(message)s) %(name)s - Logger name %(pathname)s - Full pathname to file containing the logging call %(process)d - Process ID %(processName)s - Process name %(programname)s - System programname %(relativeCreated)d - Time as integer in milliseconds when logging call was issued, relative to the time when logging module was loaded %(thread)d - Thread ID %(threadName)s - Thread name %(username)s - System username

来源:

Coloredlogs包

日志库

我修改了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)

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

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