Python 日志 - 仅对文件处理程序使用 exc_info

4 投票
2 回答
3269 浏览
提问于 2025-04-16 18:37

我定义了根日志记录器和它的处理器:

_root = logging.getLogger()
_sh = logging.StreamHandler()
_fh = logging.FileHandler('./error.log', delay = True)
_root.addHandler(_sh)
_root.addHandler(_fh)

还有模块的日志记录实例:

_log = logging.getLogger("Main")
# In other file
_log = logging.getLogger("Configuration")

现在我在try..except块中调用_log.exception

_log.exception("Test")

现在我在控制台和文件中都能看到错误追踪信息。我尝试通过控制台处理器来抑制打印错误信息,但文件处理器却没有效果:

class _TraceBackFilter(logging.Filter):
    def filter(self, rec):
        rec.exc_info = None
        return True
_sh = logging.StreamHandler()
_sh.addFilter(_TraceBackFilter())
_root.addHandler(_sh)

这个方法在文件和控制台处理器上都有效,错误追踪信息完全被去掉了,但我只想在控制台去掉。有没有办法只对控制台处理器抑制错误信息,而不影响文件处理器呢?

编辑:

我修改了_TraceBackFilter类。

class _TraceBackFilter(logging.Filter):
    def filter(self, rec):
        if rec.exc_info:
            logging.getLogger(rec.name).log(rec.levelno, rec.getMessage())
            return False
        else:
            return True

现在在控制台处理器上有效了,但在文件中我得到了重复的消息,一个有错误追踪信息,一个没有。

2 个回答

0

如果先处理的是_sh这个处理器,并且使用了那个过滤器,那么看起来它可能在修改实际的错误追踪对象。因为同一个错误追踪对象被传递给了_sh和_fh,所以_fh接收到的就是已经被修改过的错误追踪。

你可以选择在那个过滤器里创建一个新的错误追踪对象,不带exc_info,或者也可以考虑调换顺序,让_addHandler先在_fh上调用。

6

为你的控制台处理器创建一个 logging.Formatter 的子类,这个子类的 formatException 方法会返回一个空字符串。

异常信息会被缓存到记录中(在 exc_text 属性里):如果这个值是假的(比如空字符串),那么 formatException() 方法会被调用来重新填充这个信息,否则就不会被调用。所以在你的格式化类里,你可能需要重写 format() 方法,并在调用父类的 format() 方法之前,把 record.exc_text 设置为一个假的值,以确保你重写的 formatException() 能被调用。比如(未测试):

class NoExceptionFormatter(logging.Formatter):
    def format(self, record):
        record.exc_text = '' # ensure formatException gets called
        return super(NoExceptionFormatter, self).format(record)

    def formatException(self, record):
        return ''

撰写回答