私は10個のウェブサイトを解析し、データファイルを見つけ、ファイルを保存し、そしてそれらを解析してNumPyライブラリですぐに使えるデータを作るプログラムを書いています。このファイルが不適切なリンク、不適切な形式のXML、入力されていないエントリ、およびその他に分類していないものを介して発生するエラーには、 トン があります。私は最初このようなエラーを処理するためにこのプログラムを作りました:
try:
do_stuff()
except:
pass
しかし今、私はエラーをログに記録したいです。
try:
do_stuff()
except Exception, err:
print Exception, err
これは後で確認するためにログファイルに出力されることに注意してください。これは通常非常に無駄なデータを出力します。 try-exceptが例外をインターセプトせずにエラーが発生したときに出力されたものとまったく同じ行を印刷することを望みますが、プログラムがforループにネストされているため、プログラムを停止させたくありません。完成まで見てください。
他の回答から、 traceback モジュールがすでに指摘されています。
print_exc
を使用すると、場合によっては期待通りの結果が得られないことがあります。 Python 2.xでは:
import traceback
try:
raise TypeError("Oups!")
except Exception, err:
try:
raise TypeError("Again !?!")
except:
pass
traceback.print_exc()
...例外lastのトレースバックを表示します。
Traceback (most recent call last):
File "e.py", line 7, in <module>
raise TypeError("Again !?!")
TypeError: Again !?!
元のtracebackにアクセスする必要がある場合は、 exc_info
から返されるexception infosをローカル変数にキャッシュして表示することが解決策の1つです print_exception
を使う:
import traceback
import sys
try:
raise TypeError("Oups!")
except Exception, err:
try:
exc_info = sys.exc_info()
# do you usefull stuff here
# (potentially raising an exception)
try:
raise TypeError("Again !?!")
except:
pass
# end of useful stuff
finally:
# Display the *original* exception
traceback.print_exception(*exc_info)
del exc_info
プロデュース:
Traceback (most recent call last):
File "t.py", line 6, in <module>
raise TypeError("Oups!")
TypeError: Oups!
ただし、これに関する落とし穴はほとんどありません。
sys_info
のドキュメントより:
例外を処理している関数内のローカル変数にトレースバックの戻り値を代入すると、 循環参照 が発生します。これにより、同じ関数内のローカル変数またはトレースバックによって参照されるものがガベージコレクトされるのを防ぐことができます。 [...] トレースバックが必要な場合は、使用後に必ず削除してください (try ... finallyステートメントを使用するのが最善です)
しかし、同じ文書から:
Python 2.2以降、ガベージコレクションが有効になって到達不能になった場合、このようなサイクルは自動的に再利用されます 。ただし、サイクルの作成を回避する方が効率的です。
一方、トレースバックに関連付けられているにアクセスできるようにすることで、Python 3はそれほど驚くべき結果を生み出しません。
import traceback
try:
raise TypeError("Oups!")
except Exception as err:
try:
raise TypeError("Again !?!")
except:
pass
traceback.print_tb(err.__traceback__)
...が表示されます。
File "e3.py", line 4, in <module>
raise TypeError("Oups!")
traceback.format_exc()
または sys.exc_info()
は、それがあなたが望むものであればより多くの情報を生み出すでしょう。
import traceback
import sys
try:
do_stuff()
except Exception:
print(traceback.format_exc())
# or
print(sys.exc_info()[0])
プログラムを停止せずにフルトレースバックを表示する方法
エラーでプログラムを停止したくない場合は、try/exceptでそのエラーを処理する必要があります。
try:
do_something_that_might_error()
except Exception as error:
handle_the_error(error)
フルトレースバックを抽出するには、標準ライブラリのtraceback
モジュールを使います。
import traceback
そして、完全なスタックトレースを取得することを実証するために、きわめて複雑なスタックトレースを作成するには、次のようにします。
def raise_error():
raise RuntimeError('something bad happened!')
def do_something_that_might_error():
raise_error()
フルトレースバックを print にするには、traceback.print_exc
メソッドを使用します。
try:
do_something_that_might_error()
except Exception as error:
traceback.print_exc()
どの印刷物:
Traceback (most recent call last):
File "<stdin>", line 2, in <module>
File "<stdin>", line 2, in do_something_that_might_error
File "<stdin>", line 2, in raise_error
RuntimeError: something bad happened!
ただし、ベストプラクティスは、ロガーを自分のモジュール用に設定することです。それはモジュールの名前を知っていて、レベルを変えることができるでしょう(他の属性の中でも、例えばハンドラーのように)
import logging
logging.basicConfig(level=logging.DEBUG)
logger = logging.getLogger(__name__)
その場合は、代わりにlogger.exception
関数を使用します。
try:
do_something_that_might_error()
except Exception as error:
logger.exception(error)
どのログ:
ERROR:__main__:something bad happened!
Traceback (most recent call last):
File "<stdin>", line 2, in <module>
File "<stdin>", line 2, in do_something_that_might_error
File "<stdin>", line 2, in raise_error
RuntimeError: something bad happened!
あるいは、単に文字列が欲しいだけの場合は、代わりにtraceback.format_exc
関数が必要です。
try:
do_something_that_might_error()
except Exception as error:
logger.debug(traceback.format_exc())
どのログ:
DEBUG:__main__:Traceback (most recent call last):
File "<stdin>", line 2, in <module>
File "<stdin>", line 2, in do_something_that_might_error
File "<stdin>", line 2, in raise_error
RuntimeError: something bad happened!
そして、3つのオプションすべてについて、エラーが発生したときと同じ出力が得られます。
>>> do_something_that_might_error()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 2, in do_something_that_might_error
File "<stdin>", line 2, in raise_error
RuntimeError: something bad happened!
最初に、ロギングにprint
sを使用しないでください。それを行うための安定した、実績のある、よく考えられたstdlibモジュールがあります: logging
。間違いなくshould代わりに使用してください。
第二に、ネイティブで単純なアプローチがある場合、無関係なツールでmessを実行しようとしないでください。ここにあります:
log = logging.getLogger(__name__)
try:
call_code_that_fails()
except MyError:
log.exception('Any extra info you want to see in your logs')
それでおしまい。これで完了です。
log.exception
が実際に行っているのは、単にlog.error
の呼び出しです(つまり、レベルERROR
のイベントをログに記録します)andトレースバックを出力しますその後。
さて、ここにいくつかの考慮事項があります:
traceback
を使用したり、exc_info=True
でロガーを呼び出したり、sys.exc_info
で手を汚したりしないのはなぜですか?まあ、という理由だけで!それらはすべて異なる目的のために存在します。たとえば、traceback.print_exc
の出力は、インタープリター自体が生成するトレースバックとは少し異なります。あなたがそれを使用する場合、あなたはあなたのログを読む人を混乱させるでしょう、彼らは彼らに対して彼らの頭を叩きます。
exc_info=True
を渡して呼び出しをログに記録するのは不適切です。 しかし、回復可能なエラーをキャッチし、トレースバックを使用して(たとえばINFO
レベルを使用して)ログを記録したい場合にも便利です、なぜならlog.exception
は、1つのレベルのログのみを生成します-ERROR
。
そして、sys.exc_info
をいじることはできる限り避けるべきです。それは単なるパブリックインターフェイスではなく、内部インターフェイスです-あなたが何をしているかを明確に知っているなら、あなたはcanそれを使用します。例外を印刷するだけではありません。
@Aaron Hallの回答に加えて、ログに記録していてもlogging.exception()
を使用したくない場合(ERRORレベルでログを記録するため)、低いレベルを使用してexc_info=True
を渡すことができます。例えば.
try:
do_something_that_might_error()
except Exception:
logger.info('General exception noted.', exc_info=True)
エラーが発生する可能性がある最も内側のループの内側にtry/exceptを配置する必要があります。
for i in something:
for j in somethingelse:
for k in whatever:
try:
something_complex(i, j, k)
except Exception, e:
print e
try:
something_less_complex(i, j)
except Exception, e:
print e
... 等々
言い換えれば、try /で失敗する可能性のあるステートメントを、可能な限り特定のものを除いて、できるだけ内側のループでラップする必要があります。
preciseスタックトレースを文字列として取得するには、それをまたぐためのtry/exceptがない場合はwouldが発生しています。違反している例外.
desired_trace = traceback.format_exc(sys.exc_info())
これを使用する方法は次のとおりです(flaky_func
が定義されていて、log
がお気に入りのロギングシステムを呼び出すと仮定します)。
import traceback
import sys
try:
flaky_func()
except KeyboardInterrupt:
raise
except Exception:
desired_trace = traceback.format_exc(sys.exc_info())
log(desired_trace)
Ctrl-Cを使用してプログラムを強制終了できるように、KeyboardInterrupt
sをキャッチして再生成することをお勧めします。ロギングは質問の範囲外ですが、良い選択肢は logging です。 sys および traceback モジュールの資料。
この答えについてのコメント のコメント:print(traceback.format_exc())
は私にとってtraceback.print_exc()
よりも良い仕事をしています。後者では、hello
がトレースバックテキストと奇妙に "混在する"ことがあります。両方とも同時にstdoutまたはstderrに書き込みたい場合、(少なくともテキストエディタの内部からビルドしてその出力を[ビルド結果]パネル).
トレースバック(最新のコールが最後)
ファイル "C:\ Users\User\Desktop\test.py"、7行目
地獄 do_stuff()
do_stuff内のファイル "C:\ Users\User\Desktop\test.py"、4行目
1/0
ZeroDivisionError:整数除算またはゼロによるモジュロ
o
[0.1秒で終了]
だから私は使用します:
import traceback, sys
def do_stuff():
1/0
try:
do_stuff()
except Exception:
print(traceback.format_exc())
print('hello')
traceback モジュールが必要です。それはあなたがPythonが通常するようにあなたにスタックダンプを印刷させるでしょう。特に、 print_last 関数は最後の例外とスタックトレースを表示します。
私はこれが他の答えのどれにも言及されているのを見ません。なんらかの理由でExceptionオブジェクトを渡しているなら...
Python 3.5以降では、 traceback.TracebackException.from_exception()を使用して、Exceptionオブジェクトからトレースを取得できます。例えば:
import traceback
def stack_lvl_3():
raise Exception('a1', 'b2', 'c3')
def stack_lvl_2():
try:
stack_lvl_3()
except Exception as e:
# raise
return e
def stack_lvl_1():
e = stack_lvl_2()
return e
e = stack_lvl_1()
tb1 = traceback.TracebackException.from_exception(e)
print(''.join(tb1.format()))
ただし、上記のコードは次のようになります。
Traceback (most recent call last):
File "exc.py", line 10, in stack_lvl_2
stack_lvl_3()
File "exc.py", line 5, in stack_lvl_3
raise Exception('a1', 'b2', 'c3')
Exception: ('a1', 'b2', 'c3')
これは、stack_lvl_2()
で例外が発生し、傍受されなかった場合に画面に表示されたものとは対照的に、スタックの2レベルにすぎません(# raise
行のコメントを外します)。
私が理解しているように、それは例外が発生した時にスタックの現在のレベル、この場合はstack_lvl_3()
のみを記録するからです。それがスタックを介して渡されるにつれて、その__traceback__
にもっと多くのレベルが追加されています。しかし、それをstack_lvl_2()
で傍受しました。つまり、記録されるのはレベル3と2だけでした。標準出力に表示される完全なトレースを取得するには、最高(最低)レベルで捕捉する必要があります。
import traceback
def stack_lvl_3():
raise Exception('a1', 'b2', 'c3')
def stack_lvl_2():
stack_lvl_3()
def stack_lvl_1():
stack_lvl_2()
try:
stack_lvl_1()
except Exception as exc:
tb = traceback.TracebackException.from_exception(exc)
print('Handled at stack lvl 0')
print(''.join(tb.stack.format()))
結果は次のとおりです。
Handled at stack lvl 0
File "exc.py", line 17, in <module>
stack_lvl_1()
File "exc.py", line 13, in stack_lvl_1
stack_lvl_2()
File "exc.py", line 9, in stack_lvl_2
stack_lvl_3()
File "exc.py", line 5, in stack_lvl_3
raise Exception('a1', 'b2', 'c3')
スタック印刷が異なり、最初と最後の行がなくなっていることに注意してください。それは 違うformat()
だからです。
可能な限り例外が発生した場所から遠く離れて例外をインターセプトすると、より単純なコードになり、同時により多くの情報が得られます。
traceback.format_exception
を使用して例外オブジェクトからフルトレースバックを文字列として取得する
例外オブジェクトしかない場合は、Python 3のコードの任意の場所からトレースバックを文字列として取得できます。
import traceback
''.join(traceback.format_exception(None, exc_obj, exc_obj.__traceback__))
完全な例:
#!/usr/bin/env python3
import traceback
def f():
g()
def g():
raise Exception('asdf')
try:
g()
except Exception as e:
exc = e
tb_str = ''.join(traceback.format_exception(None, exc_obj, exc_obj.__traceback__))
print(tb_str)
出力:
Traceback (most recent call last):
File "./main.py", line 12, in <module>
g()
File "./main.py", line 9, in g
raise Exception('asdf')
Exception: asdf
ドキュメント: https://docs.python.org/3.7/library/traceback.html#traceback.format_exception
Python 3.7.3でテスト済み。
1つのライナー:
import traceback
traceback.print_exc()
traceback
モジュールを使用します。これは、except:
内にある場合に現在の例外を自動的に取得します。