【问题标题】:Getting a more useful 'logging' module error output in python在 python 中获得更有用的“日志记录”模块错误输出
【发布时间】:2011-08-01 12:53:21
【问题描述】:

我正在使用python的logger模块(python版本3.x,但应该没关系),我注意到格式字符串中的错误报告如下:

Traceback (most recent call last):
  File "/usr/lib/python3.1/logging/__init__.py", line 770, in emit
    msg = self.format(record)
  File "/usr/lib/python3.1/logging/__init__.py", line 650, in format
    return fmt.format(record)
  File "/usr/lib/python3.1/logging/__init__.py", line 438, in format
    record.message = record.getMessage()
  File "/usr/lib/python3.1/logging/__init__.py", line 308, in getMessage
    msg = msg % self.args
TypeError: %d format: a number is required, not str

如您所见,没有提及实际错误(在我的代码中)在哪里。顺便说一句,这是我的代码中的错误:

logging.debug('This is a string %d', str(foo))

%s 中更改%d 解决了这个问题。

我的问题是:如何从logging 模块输出中获得一些更有用的信息?我必须编写自己的记录器吗?我在哪里调整logger 模块?

【问题讨论】:

  • 我的想法是,如果您的日志记录调用错误,最好静默失败,而不是让应用程序从日志记录中获取异常。在这种想法下,模块应该故意打印(或者最好在 ERROR 处记录​​)调用上方的所有堆栈帧,而不仅仅是异常帧。我建议在 Python 邮件列表中提出这个问题。可能是为用户准备的。

标签: python python-3.x


【解决方案1】:

Unutbu 打败了我,正要发布这个。但无论如何它都在这里:

您可以尝试对您正在使用的任何处理程序进行子类化(下面使用 StreamHandler 的示例)并使用将其包装在 try: 块中的函数覆盖格式方法

import traceback, logging

class MyStreamHandler(logging.StreamHandler):
    def format(self, record):
        try:
            return logging.StreamHandler.format(self, record)
        except TypeError:
            # Print a stack trace that includes the original log call
            traceback.print_stack() 


if __name__ == "__main__":
    log = logging.getLogger("testlogger")
    handler = MyStreamHandler()

    log.addHandler(handler)

    log.error("Try interpolating an int correctly: %i", 1)

    log.error("Now try passing a string to an int: %d", 'abc')

    log.error("And then a string to a string %s", 'abc')

给我:

Try interpolating an int correctly: 1
  File "logtest2.py", line 19, in ?
    log.error("Now try passing a string to an int: %d", 'abc')
  File "/usr/lib64/python2.4/logging/__init__.py", line 999, in error
    apply(self._log, (ERROR, msg, args), kwargs)
  File "/usr/lib64/python2.4/logging/__init__.py", line 1079, in _log
    self.handle(record)
  File "/usr/lib64/python2.4/logging/__init__.py", line 1089, in handle
    self.callHandlers(record)
  File "/usr/lib64/python2.4/logging/__init__.py", line 1126, in callHandlers
    hdlr.handle(record)
  File "/usr/lib64/python2.4/logging/__init__.py", line 642, in handle
    self.emit(record)
  File "/usr/lib64/python2.4/logging/__init__.py", line 731, in emit
    msg = self.format(record)
  File "logtest2.py", line 8, in format
    traceback.print_stack()
None
And then a string to a string abc

我不会将其留在任何生产代码中,但它应该可以帮助您找到类似

的内容
log.error("%d", 'a string')

【讨论】:

  • 我更喜欢你的回答,因为它最后显示错误消息,而不是在堆的顶部。谢谢。
【解决方案2】:

如果我对您的理解正确,这里的问题是回溯没有给您任何指示错误源自代码中的何处。不知何故,你不得不追查这条线

logging.debug('This is a string %d', str(foo))

你自己。

日志记录模块的设计使得在 emit() 调用期间发生的异常由处理程序的 handleError 方法处理:

def handleError(self, record):
    """
    Handle errors which occur during an emit() call.

    This method should be called from handlers when an exception is
    encountered during an emit() call. If raiseExceptions is false,
    exceptions get silently ignored. This is what is mostly wanted
    for a logging system - most users will not care about errors in
    the logging system, they are more interested in application errors.
    You could, however, replace this with a custom handler if you wish.
    The record which was being processed is passed in to this method.
    """

您可以重写此方法以查看完整的回溯:

    import sys
    import logging

    class MyStreamHandler(logging.StreamHandler):
        def handleError(self, record):
            raise

    if __name__ == '__main__':
        console = MyStreamHandler()
        logger=logging.getLogger(__name__)
        logger.setLevel(logging.DEBUG)
        logger.addHandler(console)
        logger.debug('%d','ahh')

产量

Traceback (most recent call last):
  File "/tmp/test.py", line 25, in <module>
    logger.debug('%d','ahh')
  File "/usr/lib/python2.6/logging/__init__.py", line 1036, in debug
    self._log(DEBUG, msg, args, **kwargs)
  File "/usr/lib/python2.6/logging/__init__.py", line 1165, in _log
    self.handle(record)
  File "/usr/lib/python2.6/logging/__init__.py", line 1175, in handle
    self.callHandlers(record)
  File "/usr/lib/python2.6/logging/__init__.py", line 1212, in callHandlers
    hdlr.handle(record)
  File "/usr/lib/python2.6/logging/__init__.py", line 673, in handle
    self.emit(record)
  File "/usr/lib/python2.6/logging/__init__.py", line 796, in emit
    self.handleError(record)
  File "/usr/lib/python2.6/logging/__init__.py", line 768, in emit
    msg = self.format(record)
  File "/usr/lib/python2.6/logging/__init__.py", line 648, in format
    return fmt.format(record)
  File "/usr/lib/python2.6/logging/__init__.py", line 436, in format
    record.message = record.getMessage()
  File "/usr/lib/python2.6/logging/__init__.py", line 306, in getMessage
    msg = msg % self.args
TypeError: %d format: a number is required, not str

而使用通常的 StreamHandler,你只能得到:

Traceback (most recent call last):
  File "/usr/lib/python2.6/logging/__init__.py", line 768, in emit
    msg = self.format(record)
  File "/usr/lib/python2.6/logging/__init__.py", line 648, in format
    return fmt.format(record)
  File "/usr/lib/python2.6/logging/__init__.py", line 436, in format
    record.message = record.getMessage()
  File "/usr/lib/python2.6/logging/__init__.py", line 306, in getMessage
    msg = msg % self.args
TypeError: %d format: a number is required, not str

【讨论】:

  • 谢谢,这正是我所希望的。有点令人不安的是,这样的例子不在本教程的第 2 行。但也许我看起来不够努力。谢谢。
猜你喜欢
  • 2018-05-27
  • 2011-11-02
  • 2011-05-19
  • 1970-01-01
  • 2011-05-09
  • 2013-09-18
  • 2012-09-14
  • 2020-11-03
  • 2020-08-11
相关资源
最近更新 更多