faulthandler — Python 트레이스백 덤프
faulthandler — Python 트레이스백 덤프
버전 3.3에 추가됨.
이 모듈은 명시적으로, 결함(fault) 시, 타임아웃 후, 또는 사용자 신호에 따라 Python 트레이스백을 덤프하는 함수들을 담고 있어요. faulthandler.enable()을 호출하면 SIGSEGV, SIGFPE, SIGABRT, SIGBUS, SIGILL 신호에 대한 결함 핸들러를 설치해요. PYTHONFAULTHANDLER 환경 변수를 설정하거나 -X faulthandler 명령줄 옵션을 써서 시작 시 활성화할 수도 있어요.
출처: Python 표준 라이브러리
본문
결함 핸들러는 Apport나 Windows 결함 핸들러 같은 시스템 결함 핸들러와 호환돼요. 모듈은 sigaltstack() 함수를 사용할 수 있으면 신호 핸들러용 대체 스택을 사용해요. 그래서 스택 오버플로에서도 트레이스백을 덤프할 수 있어요.
결함 핸들러는 치명적인 경우에 호출되므로 신호-안전 함수만 사용할 수 있어요(예: 힙에 메모리를 할당할 수 없어요). 이 제한 때문에 트레이스백 덤프는 일반 Python 트레이스백에 비해 최소한으로 제한돼요.
- ASCII만 지원돼요. 인코딩에는
backslashreplace오류 핸들러가 사용돼요. - 각 문자열은 500자로 제한돼요.
- 파일명, 함수명, 줄 번호만 표시돼요(소스 코드는 없음).
- 100프레임, 100스레드로 제한돼요.
- 순서가 반대예요: 가장 최근 호출이 먼저 표시돼요.
기본적으로 Python 트레이스백은 sys.stderr에 쓰여져요. 트레이스백을 보려면 애플리케이션을 터미널에서 실행해야 해요. 대신 로그 파일을 faulthandler.enable()에 전달할 수도 있어요.
모듈은 C로 구현돼 있어서, 크래시나 Python이 교착 상태일 때도 트레이스백을 덤프할 수 있어요.
Python 개발 모드는 Python 시작 시 faulthandler.enable()을 호출해요.
트레이스백 덤프
faulthandler.dump_traceback(file=sys.stderr, all_threads=True)
모든 스레드의 트레이스백을 file에 덤프해요. all_threads가 False면 현재 스레드만 덤프해요.
트레이스백 객체를 출력하는 데 쓸 수 있는 traceback.print_tb()도 참고하세요.
버전 3.5에서 변경: 이 함수에 파일 디스크립터를 전달하는 지원이 추가됨.
C 스택 덤프
버전 3.14에 추가됨.
faulthandler.dump_c_stack(file=sys.stderr)
현재 스레드의 C 스택 트레이스를 file에 덤프해요.
Python 빌드가 이를 지원하지 않거나 운영체제가 스택 트레이스를 제공하지 않으면, 덤프된 C 스택 대신 오류를 출력해요.
C 스택 호환성
시스템이 C 레벨 backtrace(3) 또는 dladdr1(3)을 지원하지 않으면 C 스택 덤프가 동작하지 않아요. 스택 대신 오류가 출력돼요.
또한 일부 컴파일러는 CPython의 C 스택 덤프 구현을 지원하지 않아요. 그 결과, 운영체제가 스택 덤프를 지원하더라도 스택 대신 다른 오류가 출력될 수 있어요.
참고 — C 스택 덤프는 호출 스택에 있는 바이너리의 DWARF 레벨에 따라 임의로 느릴 수 있어요.
결함 핸들러 상태
faulthandler.enable(file=sys.stderr, all_threads=True, c_stack=True)
결함 핸들러를 활성화해요: SIGSEGV, SIGFPE, SIGABRT, SIGBUS, SIGILL 신호에 대한 핸들러를 설치해서 Python 트레이스백을 덤프해요. all_threads가 True면 실행 중인 모든 스레드의 트레이스백을 생성해요. 그렇지 않으면 현재 스레드만 덤프해요.
file은 결함 핸들러가 비활성화될 때까지 열어 두어야 해요: 파일 디스크립터 이슈를 참고하세요.
c_stack가 True면, 시스템이 지원하지 않는 경우가 아니라면 Python 트레이스백 뒤에 C 스택 트레이스를 출력해요. 호환성에 대한 자세한 내용은 dump_c_stack()을 참고하세요.
버전 3.5에서 변경: 파일 디스크립터 전달 지원 추가.
버전 3.6에서 변경: Windows에서 Windows 예외용 핸들러도 설치됨.
버전 3.10에서 변경: all_threads가 참이면 가비지 컬렉터 컬렉션이 실행 중인지 덤프가 언급함.
버전 3.14에서 변경: GIL이 비활성화되면 데이터 경쟁 위험을 막기 위해 현재 스레드만 덤프됨.
버전 3.14에서 변경: c_stack이 참이면 덤프가 C 스택 트레이스를 표시함.
faulthandler.disable()
결함 핸들러를 비활성화해요: enable()이 설치한 신호 핸들러를 제거해요.
faulthandler.is_enabled()
결함 핸들러가 활성화돼 있는지 확인해요.
타임아웃 후 트레이스백 덤프
faulthandler.dump_traceback_later(timeout, repeat=False, file=sys.stderr, exit=False)
timeout 초 후에, 또는 repeat가 True면 timeout 초마다 모든 스레드의 트레이스백을 덤프해요. exit가 True면 트레이스백을 덤프한 뒤 status=1로 _exit()를 호출해요. (_exit()는 프로세스를 즉시 종료하므로 파일 버퍼 플러시 같은 정리는 하지 않는다는 점을 기억하세요.) 함수가 두 번 호출되면 새 호출이 이전 매개변수를 대체하고 타임아웃을 리셋해요. 타이머는 초 단위 미만의 해상도를 가져요.
file은 트레이스백이 덤프되거나 cancel_dump_traceback_later()가 호출될 때까지 열어 두어야 해요: 파일 디스크립터 이슈 참고.
이 함수는 watchdog 스레드를 사용해 구현돼요.
버전 3.5에서 변경: 파일 디스크립터 전달 지원 추가. 버전 3.7에서 변경: 이 함수는 이제 항상 사용 가능함.
faulthandler.cancel_dump_traceback_later()
마지막 dump_traceback_later() 호출을 취소해요.
사용자 신호에 의한 트레이스백 덤프
faulthandler.register(signum, file=sys.stderr, all_threads=True, chain=False)
사용자 신호를 등록해요: 모든 스레드의 트레이스백(all_threads가 False면 현재 스레드)을 file에 덤프하도록 signum 신호에 대한 핸들러를 설치해요. chain이 True면 이전 핸들러를 호출해요.
file은 unregister()로 신호가 등록 해제될 때까지 열어 두어야 해요: 파일 디스크립터 이슈 참고.
Windows에서는 사용할 수 없어요.
버전 3.5에서 변경: 파일 디스크립터 전달 지원 추가.
faulthandler.unregister(signum)
사용자 신호를 등록 해제해요: register()가 설치한 signum 신호의 핸들러를 제거해요. 신호가 등록돼 있었다면 True, 아니면 False를 돌려줘요.
Windows에서는 사용할 수 없어요.
파일 디스크립터 이슈
enable(), dump_traceback_later(), register()는 자신의 file 인자의 파일 디스크립터를 유지해요. 파일이 닫히고 그 파일 디스크립터가 새 파일에 재사용되거나, os.dup2()로 파일 디스크립터를 대체하면 트레이스백이 다른 파일에 쓰여질 수 있어요. 파일이 교체될 때마다 이 함수들을 다시 호출하세요.
예제
Linux에서 결함 핸들러를 활성화하지 않았을 때와 했을 때의 세그멘테이션 오류 예제예요.
$ python -c "import ctypes; ctypes.string_at(0)"
Segmentation fault
$ python -q -X faulthandler
>>> import ctypes
>>> ctypes.string_at(0)
Fatal Python error: Segmentation fault
Current thread 0x00007fb899f39700 (most recent call first):
File "/opt/python/Lib/ctypes/__init__.py", line 486 in string_at
File "<stdin>", line 1 in <module>
Current thread's C stack trace (most recent call first):
Binary file "/opt/python/python", at _Py_DumpStack+0x42 [0x5b27f7d7147e]
Binary file "/opt/python/python", at +0x32dcbd [0x5b27f7d85cbd]
Binary file "/opt/python/python", at +0x32df8a [0x5b27f7d85f8a]
Binary file "/usr/lib/libc.so.6", at +0x3def0 [0x77b73226bef0]
Binary file "/usr/lib/libc.so.6", at +0x17ef9c [0x77b7323acf9c]
Binary file "/opt/python/build/lib.linux-x86_64-3.14/_ctypes.cpython-314d-x86_64-linux-gnu.so", at +0xcdf6 [0x77b7315dddf6]
Binary file "/usr/lib/libffi.so.8", at +0x7976 [0x77b73158f976]
Binary file "/usr/lib/libffi.so.8", at +0x413c [0x77b73158c13c]
Binary file "/usr/lib/libffi.so.8", at ffi_call+0x12e [0x77b73158ef0e]
Binary file "/opt/python/build/lib.linux-x86_64-3.14/_ctypes.cpython-314d-x86_64-linux-gnu.so", at +0x15a33 [0x77b7315e6a33]
Binary file "/opt/python/build/lib.linux-x86_64-3.14/_ctypes.cpython-314d-x86_64-linux-gnu.so", at +0x164fa [0x77b7315e74fa]
Binary file "/opt/python/build/lib.linux-x86_64-3.14/_ctypes.cpython-314d-x86_64-linux-gnu.so", at +0xc624 [0x77b7315dd624]
Binary file "/opt/python/python", at _PyObject_MakeTpCall+0xce [0x5b27f7b73883]
Binary file "/opt/python/python", at +0x11bab6 [0x5b27f7b73ab6]
Binary file "/opt/python/python", at PyObject_Vectorcall+0x23 [0x5b27f7b73b04]
Binary file "/opt/python/python", at _PyEval_EvalFrameDefault+0x490c [0x5b27f7cbb302]
Binary file "/opt/python/python", at +0x2818e6 [0x5b27f7cd98e6]
Binary file "/opt/python/python", at +0x281aab [0x5b27f7cd9aab]
Binary file "/opt/python/python", at PyEval_EvalCode+0xc5 [0x5b27f7cd9ba3]
Binary file "/opt/python/python", at +0x255957 [0x5b27f7cad957]
Binary file "/opt/python/python", at +0x255ab4 [0x5b27f7cadab4]
Binary file "/opt/python/python", at _PyEval_EvalFrameDefault+0x6c3e [0x5b27f7cbd634]
Binary file "/opt/python/python", at +0x2818e6 [0x5b27f7cd98e6]
Binary file "/opt/python/python", at +0x281aab [0x5b27f7cd9aab]
Binary file "/opt/python/python", at +0x11b6e1 [0x5b27f7b736e1]
Binary file "/opt/python/python", at +0x11d348 [0x5b27f7b75348]
Binary file "/opt/python/python", at +0x11d626 [0x5b27f7b75626]
Binary file "/opt/python/python", at PyObject_Call+0x20 [0x5b27f7b7565e]
Binary file "/opt/python/python", at +0x32a67a [0x5b27f7d8267a]
Binary file "/opt/python/python", at +0x32a7f8 [0x5b27f7d827f8]
Binary file "/opt/python/python", at +0x32ac1b [0x5b27f7d82c1b]
Binary file "/opt/python/python", at Py_RunMain+0x31 [0x5b27f7d82ebe]
<truncated rest of calls>
Segmentation fault
더 알아보기
pdb— Python 프로그램용 대화형 소스 코드 디버거.traceback— Python 프로그램의 스택 트레이스를 추출·포맷·출력하는 표준 인터페이스.