在Python中使用日志模块进行颜色记录

时间:2022-03-09 22:03:34

Let's simplify this. My goal is to make color output in terminal using logging module in Python. I want info has a green prefix, warnings have a yellow prefix and errors have a red prefix. To make it simple let's use *** as the prefix i.e.

让我们化简。我的目标是使用Python中的日志模块在终端中生成颜色输出。我想要info有一个绿色的前缀,警告有一个黄色的前缀,错误有一个红色的前缀。为了简单起见,我们使用*** *作为前缀,即。

*** log text
*** another message with another prefix color

What I have done so far

到目前为止我所做的一切

# declaration of function (global scope)
log = None
warn = None
error = None 
def build_log_funcs():
    # why I initialize it inside the function ?
    # because script doesnt have to know about logging method
    # the function just provide log  functions
    logger = logging.getLogger(__name__)
    logger.setLevel(logging.INFO)

    sh = logging.StreamHandler()
    # LOG_FORMAT just global variable with pattern including %(levelmarks)s
    # it will be replaced with ** with proper color 
    formatter = logging.Formatter(LOG_FORMAT)
    sh.setFormatter(formatter)
    logger.addHandler(sh)

    def make_log_func(func, color, is_exit = False):
        color_string = "\x1b[{};1m***\x1b[0m".format(color)
        def newfunc(*args, **kwargs):
            func(*args, extra={'levelmarks':color_string}, **kwargs)
            if is_exit:
                sys.exit(-1)

        return newfunc
    # 32, 33, 31 are color codes
    log = make_log_func(logger.info, 32)
    warn = make_log_func(logger.warning, 33)
    error = make_log_func(logger.error, 31, is_exit = True)

    return log, warn, error

And use it as

和使用它

log, warn, error = build_log_funcs()

It works but what I don't like: (from small to big problems)

它起作用,但我不喜欢的是:(从小问题到大问题)

  1. I hide the capabilities of logging module. For example enabling/disabling debug messages
  2. 我隐藏了日志模块的功能。例如,启用/禁用调试消息
  3. I should use global declaration of functions before their initialization because I can't call a function before its declaration.
  4. 我应该在函数初始化之前使用全局声明,因为我不能在函数声明之前调用它。
  5. It's too difficult to read and maintain the code. I believe that everything should be as simple as possible.
  6. 读取和维护代码太困难了。我相信一切都应该尽可能地简单。

Why don't I just make simple log, warn, simple function? I don't know. logging is the very comprehensive module so may be I will need its features in the future.

为什么我不做一个简单的log, warn,简单的函数呢?我不知道。日志是一个非常全面的模块,所以我将来可能需要它的特性。

My question is how would you solve this problem? May be there is a simple obvious way which I don't know.

我的问题是你如何解决这个问题?也许有一个简单而明显的方法我不知道。

1 个解决方案

#1


3  

Thanks Dominic Kexel for this link. I saw this but did not pay attention to the answer. The following code is more or less suitable for me

感谢Dominic Kexel提供的链接。我看到了,但没有注意到答案。下面的代码或多或少适合我

def setup_logger(logger):
    logger.setLevel(logging.DEBUG)

    sh = logging.StreamHandler()
    formatter = logging.Formatter(LOG_FORMAT)
    sh.setFormatter(formatter)

    def decorate_emit(fn):
    # add methods we need to the class
        def new(*args):
            levelno = args[0].levelno
            if(levelno >= logging.CRITICAL):
                color = '\x1b[31;1m'
            elif(levelno >= logging.ERROR):
                color = '\x1b[31;1m'
            elif(levelno >= logging.WARNING):
                color = '\x1b[33;1m'
            elif(levelno >= logging.INFO):
                color = '\x1b[32;1m'
            elif(levelno >= logging.DEBUG):
                color = '\x1b[35;1m'
            else:
                color = '\x1b[0m'
            # add colored *** in the beginning of the message
            args[0].msg = "{0}***\x1b[0m {1}".format(color, args[0].msg)

            # new feature i like: bolder each args of message 
            args[0].args = tuple('\x1b[1m' + arg + '\x1b[0m' for arg in args[0].args)
            return fn(*args)
        return new
    sh.emit = decorate_emit(sh.emit)
    logger.addHandler(sh)

There is one flaw in this: I can't control the position of *** in the pattern but as I said it's suitable.

这有一个缺点:我无法控制模式中的***的位置,但我说过它是合适的。

#1


3  

Thanks Dominic Kexel for this link. I saw this but did not pay attention to the answer. The following code is more or less suitable for me

感谢Dominic Kexel提供的链接。我看到了,但没有注意到答案。下面的代码或多或少适合我

def setup_logger(logger):
    logger.setLevel(logging.DEBUG)

    sh = logging.StreamHandler()
    formatter = logging.Formatter(LOG_FORMAT)
    sh.setFormatter(formatter)

    def decorate_emit(fn):
    # add methods we need to the class
        def new(*args):
            levelno = args[0].levelno
            if(levelno >= logging.CRITICAL):
                color = '\x1b[31;1m'
            elif(levelno >= logging.ERROR):
                color = '\x1b[31;1m'
            elif(levelno >= logging.WARNING):
                color = '\x1b[33;1m'
            elif(levelno >= logging.INFO):
                color = '\x1b[32;1m'
            elif(levelno >= logging.DEBUG):
                color = '\x1b[35;1m'
            else:
                color = '\x1b[0m'
            # add colored *** in the beginning of the message
            args[0].msg = "{0}***\x1b[0m {1}".format(color, args[0].msg)

            # new feature i like: bolder each args of message 
            args[0].args = tuple('\x1b[1m' + arg + '\x1b[0m' for arg in args[0].args)
            return fn(*args)
        return new
    sh.emit = decorate_emit(sh.emit)
    logger.addHandler(sh)

There is one flaw in this: I can't control the position of *** in the pattern but as I said it's suitable.

这有一个缺点:我无法控制模式中的***的位置,但我说过它是合适的。

相关文章