IT/python

[python]오류 발생시 호출 스택 출력하기

심량 2020. 9. 28. 14:31

try except로 오류 발생을 처리하다 보면 개발 도중에 자주 오류가 발생할 때 오류 추적이 쉽지 않은 경우가 있습니다. vscode로 실행을 직접 할 수 있는 경우라면 GUI로 편하게 디버깅 가능하지만, vscode 가 지원하지 않는 아키텍처(예를 들면, mips라든지, mips라든지...)인 경우에는 pdb 사용법을 익혀야 되는데 gdb처럼 맘껏 잘 동작하지는 않습니다.

 

import traceback 을 하고 exception 발생했을 때 traceback.format_exc() 값을 출력해주면 됩니다.

 

try:
	....
except Exception as e:
	print('ERROR::{}, {}'.format(e, traceback.format_exec()))

작성한지 시간이 지나서(수정 시간 2024.02.15) 예외가 발생하면서 습관처럼 traceback 을 import 하고 출력하고 있다가 이런 생각이 들었습니다.

위 예제에서 e 에서는 에러 메시지 외에는 출력할 게 없을까? 최소한의 정보라도 있지 않을까?

 

그래서 혹시나 하는 마음에 예외처리 하는 부분에서 dir(e) 를 출력해봤습니다.

['__cause__', '__class__', '__context__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__setstate__', '__sizeof__', '__str__', '__subclasshook__', '__suppress_context__', '__traceback__', '__weakref__', 'args', 'with_traceback']

 

길다란데 끝에 쯤 보면 눈에 띄는 멤버가 있습니다. 바로 __traceback__ 과 with_traceback 입니다.

 

먼저 __traceback__ 을 살펴봅시다.


tb_frame, tb_lineno, tb_lasti, tb_next 를 멤버로 갖고 있습니다.


tb_frame 은 frame 입니다. sys._getframe() 을 호출했을 때 반환되는 객체와 동일합니다!!! 다만, 완전히 동일하다고 볼 수는 없는게.. 오류가 발생했을 때의 sys._getframe() 과 동일합니다. ㅎㅎ

확인할 수 있는 자세한 정보는 코드 객체를 참고하시기 바랍니다.

 

다만, 이 구조를 살펴보니 traceback.format_exc() 한 줄 호출하는 것이 좀 편해보입니다. 일일이 frame 관련 포인터를 뒤져야 그럴 듯한 스택 트레이스를 만들 수 있을테니까요. 다만 상세 backtrace 까지 필요없고 간단한 발생 위치 정도만 있어도 된다면 호출자와 발생 위치 정도만 알아도 도움이 되지 않을까 싶습니다.

저는 다음과 같이 호출자(caller)와 오류 발생한 위치의 정보를 간단히 출력해봤습니다.

print(f"ERROR:__anext__:{type(e).__name__},caller:{e.__traceback__.tb_frame.f_back.f_code.co_filename}::{e.__traceback__.tb_frame.f_back.f_code.co_name}, me:{e.__traceback__.tb_frame.f_code.co_filename}::{e.__traceback__.tb_frame.f_code.co_name} at line {e.__traceback__.tb_lineno}")

 

그러면 아래와 같이 출력되네요. 수정한 파일은 client.py 파일입니다.

ERROR:__anext__:ClientPayloadError,caller:/usr/lib/python3.7/asyncio/events.py::_run, me:/home/pi/.local/lib/python3.7/site-packages/aiohttp_sse_client/client.py::__anext__ at line 159

 

with_traceback(tb) 은 tb 라는 exception 을 with_traceback() 을 호출한 exception 으로 변환하는 기능이라고 합니다. 일반적인 추적에서는 사용할 필요가 없고 예외 클래스를 만들 때나 필요하지 않을까 싶습니다.

 

참고

https://docs.python.org/ko/3/library/traceback.html

https://docs.python.org/ko/3/reference/datamodel.html#traceback-objects

https://docs.python.org/ko/3/reference/datamodel.html#frame-objects

https://docs.python.org/ko/3/reference/datamodel.html#code-objects

https://docs.python.org/ko/3/library/exceptions.html