ある日の某Pythonアプリケーションのエラーログを眺めていると謎のエラーが...!
Traceback (most recent call last):
File "/sandbox/app.py", line 22, in <module>
main()
File "/sandbox/app.py", line 17, in main
sub()
File "/sandbox/app.py", line 10, in sub
raise Exception("sub error!")
Exception: sub error!
例外が起きたときのTracebackですね。
Exceptionに詳細が記録されていればわかりやすいのですが、上記のようになぜエラーが起きたのかわからないと困りますよね。
そんなとき、Tracebackのstackを追いかける事でそのときのローカル変数を取得できます。
こんなアプリケーションがあるとして
def sub():
d = 4
e = 5
raise Exception("sub error!")
def main():
a = 1
b = 2
c = 3
sub()
例外キャッチハンドラをこのように
import sys
import traceback
from pprint import pprint
if __name__ == "__main__":
try:
main()
except Exception:
(_, _, tb) = sys.exc_info()
for (frame, _) in traceback.walk_tb(tb):
pprint(frame)
pprint(frame.f_locals)
raise
するとあら不思議
<frame at 0x7feb8b610240, file '/sandbox/app.py', line 26, code <module>>
{'_': 22,
'__annotations__': {},
'__builtins__': <module 'builtins' (built-in)>,
'__cached__': None,
'__doc__': None,
'__file__': '/sandbox/app.py',
'__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x106dbaca0>,
'__name__': '__main__',
'__package__': None,
'__spec__': None,
'frame': <frame at 0x7feb8b610240, file '/sandbox/app.py', line 27, code <module>>,
'logging': <module 'logging' from '/usr/local/Cellar/python@3.9/3.9.13/Frameworks/Python.framework/Versions/3.9/lib/python3.9/logging/__init__.py'>,
'main': <function main at 0x107007d30>,
'pprint': <function pprint at 0x107007dc0>,
'sub': <function sub at 0x106e06160>,
'sys': <module 'sys' (built-in)>,
'tb': <traceback object at 0x10700db00>,
'traceback': <module 'traceback' from '/usr/local/Cellar/python@3.9/3.9.13/Frameworks/Python.framework/Versions/3.9/lib/python3.9/traceback.py'>}
<frame at 0x106ee6200, file '/sandbox/app.py', line 17, code main>
{'a': 1, 'b': 2, 'c': 3}
<frame at 0x106f46900, file '/sandbox/app.py', line 10, code sub>
{'d': 4, 'e': 5}
Traceback (most recent call last):
File "/sandbox/app.py", line 22, in <module>
main()
File "/sandbox/app.py", line 17, in main
sub()
File "/sandbox/app.py", line 10, in sub
raise Exception("sub error!")
Exception: sub error!
StackのFrameごとにローカル変数が出力されました。
Webアプリケーションだと例外ハンドリング層に組み込むと便利ですね。