【问题标题】:Can't find the source of exception找不到异常的来源
【发布时间】:2013-08-22 13:59:47
【问题描述】:

我正在尝试找出我们的 python 脚本崩溃的原因。

主要结构是这样的:

def main()
    try:
      dostuff
    except Exception as ex:
      import traceback
      tb = traceback.format_exc()
      import platform
      node = platform.node()
      sendMail([DEBUG_EMAIL], "Alarm exception on %s" % node, str(tb), [])

我在我们的主要错误处理中得到了这个堆栈跟踪,不是在我应该得到的错误电子邮件中。

Traceback (most recent call last):
  File "/usr/lib/python2.6/logging/__init__.py", line 799, in emit
    stream.write(fs % msg.encode("UTF-8"))
UnicodeDecodeError: 'ascii' codec can't decode byte 0xc3 in position 66: ordinal not in range(128)

据我所见,对记录器的所有写调用都在 try 块内,但由于它没有在我的电子邮件发送异常块中被捕获和处理,所以我似乎错过了一些东西。我已经检查过了,sendMail 函数根本不使用日志记录模块。所以异常不应该起源于我的异常块。

我尝试添加

sys.tracebacklimit = 10

在文件的顶部查看异常的来源,但这并没有影响任何事情。现在我不知道如何找到问题的根源。

该脚本每小时运行一次,每周仅崩溃一次,这让我认为它与输入数据有关,但仅由 dostuff() 处理。

更新:

我已经弄清楚为什么我只能得到一排堆栈跟踪。在 emit() 中我发现了这个。

        try:
            ... doing stuff, something goes boom with encoding...
        except UnicodeError:
            stream.write(fs % msg.encode("UTF-8")) Here it goes Boom again
        self.flush()
    except (KeyboardInterrupt, SystemExit):
        raise
    except:
        self.handleError(record) Which means it ends up here

handleError 函数的相关部分如下所示:

 ei = sys.exc_info()
 try:
     traceback.print_exception(ei[0], ei[1], ei[2], None, sys.stderr)

仅打印堆栈跟踪的最后一部分。

【问题讨论】:

  • 我不确定你的意思。
  • 异常似乎发生在日志包的__init__.py脚本中,所以也有可能在脚本加载时出现,在进入try块之前导入logging失败跨度>
  • @ValentinCLEMENT 添加了有关使用情况和崩溃频率的信息。
  • @ValentinCLEMENT init.py 中的那一行是写入记录的代码的一部分,所以在我看来,它应该源自对记录器的写入调用。
  • 你看过这个:stackoverflow.com/questions/9942594/…和这个:stackoverflow.com/questions/5141559/…“基本上,停止使用str从unicode转换为编码文本/字节。”

标签: python


【解决方案1】:

基本上你的问题是双重的

  1. 一个日志流不接受带有扩展字符的 8 位字符串,并抛出 UnicodeError
  2. 日志模块中存在一个愚蠢的错误,使其丢失原始回溯

异常的确切原因是这样的:

>>> 'ä'.encode('UTF-8')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
UnicodeDecodeError: 'ascii' codec can't decode byte 0xc3 in position 0: ordinal not in range(128)

但是这个异常并不是真正的问题。这是 2.6 日志记录代码的一部分; 799 是该块的最后一行。最后一行是导致问题的行。基本上,有些东西以 8 位字节字符串记录消息,UTF-8 编码,包含拉丁 1 扩展字母;但流不喜欢这样,并在 try 块中抛出 UnicodeError;

try:
    if (isinstance(msg, unicode) and
        getattr(stream, 'encoding', None)):

        # .... the string is NOT an unicode instance, so ignored
        # for brevity
    else:
        # this line throws the original exception 
        # fs is a bytestring "%s\n", and msg is a bytestring
        # with extended letters, most probably Latin 1.
        # stream.write spits out an UnicodeError on these values
        stream.write(fs % msg)
except UnicodeError:
    # now we get a useless exception report from this code
    stream.write(fs % msg.encode("UTF-8"))

因此,要调试它,您需要在上述第 799 行设置断点,并尝试所有接受以下字符串的记录器:

logging.getLogger(name).critical('Testing logger: ä')

如果您点击第 799 行然后获取异常的回溯,它可以揭示正在发生的事情...

【讨论】:

  • 好答案 :) 除了这种情况每周只发生一次左右,我真的很想改进堆栈跟踪,看看我的代码中问题的根源。我目前的计划是复制和修改日志记录模块以修复堆栈跟踪打印输出。然后当我知道错误来自哪里时,我可以重新使用标准模块。
猜你喜欢
  • 2011-08-16
  • 1970-01-01
  • 1970-01-01
  • 2018-07-01
  • 1970-01-01
  • 1970-01-01
  • 2017-05-10
  • 2012-11-20
  • 2011-12-24
相关资源
最近更新 更多