【问题标题】:How to traceback logging errors?如何追溯日志记录错误?
【发布时间】:2012-11-07 16:29:01
【问题描述】:

我使用logging 模块在我的应用程序上记录消息。

我经常会遇到格式字符串或参数的错误导致错误的情况,例如:

import logging
my_log = logging.getLogger("MyLog")
# this is obviously wrong
my_log.info('%d', "abc")

结果是一个类似下面的错误:

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

但是,它只显示日志模块内的回溯;它没有告诉我代码中发生错误的位置。

有什么办法可以解决吗?

【问题讨论】:

  • stackoverflow.com/questions/6898674/… 看起来和你有类似问题的人;有一个答案,其中包含将日志记录处理程序子类化以添加更好的堆栈跟踪的代码(包括您调用它的位置)。
  • 我无法重现您的错误,但也许将回溯限制设置为更高的值会有所帮助。 import sys; sys.traceback_limit = 10.

标签: python debugging logging error-handling


【解决方案1】:

我在查找错误源时遇到了同样的问题。日志模块处理此类异常并且不停止程序 - 这是日志模块可接受的行为。但是是抑制异常并且在处理它时没有提供足够的信息。

我发现并现在使用粗描述here

诀窍是将用于字符串格式化logging.LogRecord.getMessage 的非常基本的日志记录函数替换为使用异常处理子句包装调用的函数。
确保在使用 logger 之前进行了此替换。 这种替换也适用于您程序的其他模块。

所以你的例子会被这样修改: 请注意,我稍微修改了代码以确保会生成异常。

def print_log_record_on_error(func):
    def wrap(self, *args, **kwargs):
        try:
            return func(self, *args, **kwargs)
        except:
            import sys
            print >>sys.stderr, "Unable to create log message msg=%r, args=%r " % (
                getattr(self, 'msg', '?'), getattr(self, 'args', '?'))
            raise
    return wrap
import logging
logging.LogRecord.getMessage = print_log_record_on_error(logging.LogRecord.getMessage)

logging.basicConfig()
my_log = logging.getLogger("MyLog")
# this is obviously wrong
my_log.error('%d' , "abc")

现在它会产生更多有用的异常:

Unable to create log message msg='%d', args=('abc',) 
Traceback (most recent call last):
  File "C:\Progs\Python262\Lib\logging\__init__.py", line 760, in emit
    msg = self.format(record)
  File "C:\Progs\Python262\Lib\logging\__init__.py", line 644, in format
    return fmt.format(record)
  File "C:\Progs\Python262\Lib\logging\__init__.py", line 432, in format
    record.message = record.getMessage()
  File "C:/Users/vvlad/PycharmProjects/stackoverflow/test1.py", line 6, in wrap
    return func(self, *args, **kwargs)
  File "C:\Progs\Python262\Lib\logging\__init__.py", line 302, in getMessage
    msg = msg % self.args
TypeError: %d format: a number is required, not str

如果您有日志密集型应用程序,我建议添加选项以替换登录功能。因此,在调试模式下的代码将使用重载函数,但在生产环境中 - 它不会,因此您可以避免再进行一次异常处理的性能损失。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-06-30
    • 2012-03-26
    • 1970-01-01
    相关资源
    最近更新 更多