找不到异常的来源

时间:2013-08-20 13:31:59

标签: python

我正在尝试查找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), [])

我在主错误处理中得到了这个堆栈跟踪, not 在错误的电子邮件中我应该这样做。

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)

从我看到的所有对logger的写入调用都在try-block中,但由于它没有在我的电子邮件发送异常块中被捕获和处理,所以我似乎错过了一些东西。我已经检查过,sendMail函数根本不使用日志记录模块。所以异常不应该来自我的except-block。

我尝试添加

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)

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

1 个答案:

答案 0 :(得分:3)

基本上你的问题是双重的

  1. 一个日志流不接受带有扩展字符的8位字符串,并抛出UnicodeError
  2. 日志记录模块中存在一个愚蠢的错误,使其失去原始追溯
  3. 异常的确切原因是:

    >>> 'ä'.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编码,包含Latin-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行然后获得异常的回溯,它可以揭示正在发生的事情......