web-dev-qa-db-ja.com

Pythonで完全な例外スタックトレースを取得する方法

次のスニペット:

import traceback

def a():
    b()

def b():
    try:
        c()
    except:
        traceback.print_exc()

def c():
    assert False

a()

この出力を生成します:

Traceback (most recent call last):
  File "test.py", line 8, in b
    c()
  File "test.py", line 13, in c
    assert False
AssertionError

への呼び出しを含む完全なスタックトレースが必要な場合、何を使用すればよいですか?

それが重要であれば、Python 2.6.6

編集:私が取得したいのは、私が試みを外して例外をトップレベルに伝播させた場合と同じ情報です。このスニペットの例:

def a():
    b()

def b():
    c()

def c():
    assert False

a()

この出力を生成します:

Traceback (most recent call last):
  File "test.py", line 10, in <module>
    a()
  File "test.py", line 2, in a
    b()
  File "test.py", line 5, in b
    c()
  File "test.py", line 8, in c
    assert False
AssertionError
29
Gordon Wrigley

より良い方法があるかどうかはわかりませんが、これが私がしたことです:

import traceback
import sys

def format_exception(e):
    exception_list = traceback.format_stack()
    exception_list = exception_list[:-2]
    exception_list.extend(traceback.format_tb(sys.exc_info()[2]))
    exception_list.extend(traceback.format_exception_only(sys.exc_info()[0], sys.exc_info()[1]))

    exception_str = "Traceback (most recent call last):\n"
    exception_str += "".join(exception_list)
    # Removing the last \n
    exception_str = exception_str[:-1]

    return exception_str

def main1():
    main2()

def main2():
    try:
        main3()
    except Exception as e:
        print "Printing only the traceback above the current stack frame"
        print "".join(traceback.format_exception(sys.exc_info()[0], sys.exc_info()[1], sys.exc_info()[2]))
        print
        print "Printing the full traceback as if we had not caught it here..."
        print format_exception(e)

def main3():
    raise Exception()

if __name__ == '__main__':
    main1()

そして、これが私が得る出力です:

Printing only the traceback above the current stack frame
Traceback (most recent call last):
  File "exc.py", line 22, in main2
    main3()
  File "exc.py", line 31, in main3
    raise Exception()
Exception


Printing the full traceback as if we had not caught it here...
Traceback (most recent call last):
  File "exc.py", line 34, in <module>
    main1()
  File "exc.py", line 18, in main1
    main2()
  File "exc.py", line 22, in main2
    main3()
  File "exc.py", line 31, in main3
    raise Exception()
Exception
20
John Wernicke

これが this answer に基づく関数です。例外が存在しない場合にも機能します。

_def full_stack():
    import traceback, sys
    exc = sys.exc_info()[0]
    stack = traceback.extract_stack()[:-1]  # last one would be full_stack()
    if exc is not None:  # i.e. an exception is present
        del stack[-1]       # remove call of full_stack, the printed exception
                            # will contain the caught exception caller instead
    trc = 'Traceback (most recent call last):\n'
    stackstr = trc + ''.join(traceback.format_list(stack))
    if exc is not None:
         stackstr += '  ' + traceback.format_exc().lstrip(trc)
    return stackstr
_

print full_stack()は、スタックトレース全体を先頭まで出力します。 IPythonの_interactiveshell.py_呼び出し。とにかくそれを理解する価値はありません...

exceptブロック内からprint full_stack()が呼び出された場合、_full_stack_にはraiseまでのスタックトレースが含まれます。標準のPythonインタプリタでは、これは例外をキャッチしないときに受け取るメッセージと同じです(そのため、_del stack[-1]_が存在するのはそのため、exceptは気にしません)ブロック、ただしtryブロックについて)。

21
Tobias Kienzler

使用する

 traceback.print_stack()

http://docs.python.org/library/traceback.html#traceback.print_stack

suxmac2 $ python out.py 
  File "out.py", line 16, in <module>
    a()
  File "out.py", line 5, in a
    b()
  File "out.py", line 11, in b
    traceback.print_stack()
7
Andreas Jung


これが トビアスキエンツラーの回答 のもう少し良い変形です。同じように機能しますが、exceptブロックではなく、どこかより深い場所で呼び出すことができます。つまり、このバリアントは、次のように呼び出されたときに同じスタックを出力します

try:
   ...
except Exception:
    print full_stack()

または

def print_full_stack():
    print full_stack()

try:
   ...
except Exception:
    print_full_stack()

ここにコードがあります:

def full_stack():
    import traceback, sys
    exc = sys.exc_info()[0]
    if exc is not None:
        f = sys.exc_info()[-1].tb_frame.f_back
        stack = traceback.extract_stack(f)
    else:
        stack = traceback.extract_stack()[:-1]  # last one would be full_stack()
    trc = 'Traceback (most recent call last):\n'
    stackstr = trc + ''.join(traceback.format_list(stack))
    if exc is not None:
        stackstr += '  ' + traceback.format_exc().lstrip(trc)
    return stackstr
2
Skipor