更改一个处理程序的日志记录格式会更改所有处理程序

Changing logging format for one handler changes it for all

我想将一个记录器流式传输到多个流。更改标准格式有效,但更改 formatException 函数会改变所有格式! 不确定这是否是一项功能,我误解了什么。

请参阅下面的示例,其中我使用标准 logging.Formatter 和带有 limit 变量的修改版:

import logging, io, traceback


class TermFormatter(logging.Formatter):
    
    def __init__(self, *args, stack_limit=1, **kwargs):
        super().__init__(*args, **kwargs)    
        self.stack_limit = stack_limit
    
    def formatException(self, ei):
        """
        Format and return the specified exception information as a string.

        This default implementation just uses
        traceback.print_exception()
        """
        sio = io.StringIO()
        tb = ei[2]
        # See issues #9427, #1553375. Commented out for now.
        #if getattr(self, 'fullstack', False):
        #    traceback.print_stack(tb.tb_frame.f_back, file=sio)
        traceback.print_exception(ei[0], ei[1], tb, self.stack_limit, sio)
        s = sio.getvalue()
        sio.close()
        if s[-1:] == "\n":
            s = s[:-1]
        if self.stack_limit ==0:
            return "Hello my friend!"
        else:
            return s
        


stream_handler = logging.StreamHandler()
stream_handler.terminator = "  \n"


formatter0 = TermFormatter("F1 %(asctime)s [%(levelname)s]: %(message)s",
                           stack_limit=2)

stream_handler.setFormatter(formatter0)
stream_handler.setLevel(logging.ERROR)



#check the internals of the err logging

stream_handler2 = logging.StreamHandler()
stream_handler2.terminator = "  \n"
formatter = TermFormatter("F2 %(asctime)s [%(levelname)s]: %(message)s",
                          stack_limit=0)
stream_handler2.setFormatter(formatter)
stream_handler2.setLevel(logging.DEBUG)


term_handler = logging.StreamHandler()
term_handler.setFormatter(logging.Formatter("F3 %(asctime)s [%(levelname)s]: %(message)s"))
term_handler.setLevel(logging.DEBUG)


logger=  logging.getLogger()
logger.addHandler(stream_handler2)
logger.addHandler(stream_handler)
logger.addHandler(term_handler)

logger.error('wow!')

try:
    raise Exception('oh bad')
except:
    logger.exception("very ugly")

输出:

F2 2021-07-04 14:16:42,889 [ERROR]: wow!  
F1 2021-07-04 14:16:42,889 [ERROR]: wow!  
F3 2021-07-04 14:16:42,889 [ERROR]: wow!
F2 2021-07-04 14:16:42,890 [ERROR]: very ugly
Hello my friend!  
F1 2021-07-04 14:16:42,890 [ERROR]: very ugly
Hello my friend!  
F3 2021-07-04 14:16:42,890 [ERROR]: very ugly
Hello my friend!

我希望在最后三个日志中看到:对于 F1,限制为 2 的堆栈跟踪,对于 F2,显示什么,对于 F3,完整堆栈跟踪是默认行为。我在所有情况下都是第二种情况。

此行为的原因记录在此处:

https://docs.python.org/3/library/logging.html?highlight=exc_text#logging.Formatter.format

”请注意,格式化的异常信息缓存在属性 exc_text 中。这很有用,因为异常信息可以被 pickle 并通过网络发送,但如果您有多个 Formatter,则应小心自定义异常信息格式的子类。在这种情况下,您必须在格式化程序完成格式化后清除缓存值,以便下一个处理事件的格式化程序不会使用缓存值,而是重新计算它。 “