9

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 関数は logging モジュールをまったく使用していません。したがって、例外は私の except-block で発生するべきではありません。

追加してみました

sys.tracebacklimit = 10

ファイルの先頭で、例外の発生場所を確認しますが、それは何にも影響しませんでした。そして今、問題の原因を見つける方法についてのアイデアがありません。

スクリプトは 1 時間に 1 回実行され、クラッシュするのは 1 週間に 1 回程度です。これは、入力データに関連するものだと思わせますが、それは dostuff() によってのみ処理されます。

アップデート:

スタックトレースが 1 行しか表示されない理由がわかりました。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)

スタックトレースの最後の部分のみを出力します。

4

1 に答える 1

3

基本的にあなたの問題は2つあります

  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 でエンコードされ、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行目にヒットしてから例外のバックトレースを取得すると、何が起こっているのかを明らかにすることができます...

于 2013-08-20T14:26:46.747 に答える