Próbuję debugować skrypt wielowątkowy. Po Wyjątkiem jest podniesiony chcę:Post mortem debugowanie skryptów wielowątkowych
- Zgłoś go do systemu monitoringu (tylko drukowanie w poniższym przykładzie)
- zatrzymać cały skrypt (w tym wszystkich innych wątków)
- rozmowę wiersz debugera poubojowe w perspektywa podniesiona wyjątek
przygotować dość skomplikowany przykład, aby pokazać jak próbowałem go rozwiązać:
#!/usr/bin/env python
import threading
import inspect
import traceback
import sys
import os
import time
def POST_PORTEM_DEBUGGER(type, value, tb):
traceback.print_exception(type, value, tb)
print
if hasattr(sys, 'ps1') or not sys.stderr.isatty():
import rpdb
rpdb.pdb.pm()
else:
import pdb
pdb.pm()
sys.excepthook = POST_PORTEM_DEBUGGER
class MyThread(threading.Thread):
def __init__(self):
threading.Thread.__init__(self)
self.exception = None
self.info = None
self.the_calling_script_name = os.path.abspath(inspect.currentframe().f_back.f_code.co_filename)
def main(self):
"Virtual method to be implemented by inherited worker"
return self
def run(self):
try:
self.main()
except Exception as exception:
self.exception = exception
self.info = traceback.extract_tb(sys.exc_info()[2])[-1]
# because of bug http://bugs.python.org/issue1230540
# I cannot use just "raise" under threading.Thread
sys.excepthook(*sys.exc_info())
def __del__(self):
print 'MyThread via {} catch "{}: {}" in {}() from {}:{}: {}'.format(self.the_calling_script_name, type(self.exception).__name__, str(self.exception), self.info[2], os.path.basename(self.info[0]), self.info[1], self.info[3])
class Worker(MyThread):
def __init__(self):
super(Worker, self).__init__()
def main(self):
""" worker job """
counter = 0
while True:
counter += 1
print self
time.sleep(1.0)
if counter == 3:
pass # print 1/0
def main():
Worker().start()
counter = 1
while True:
counter += 1
time.sleep(1.0)
if counter == 3:
pass # print 1/0
if __name__ == '__main__':
main()
Sztuczka z
sys.excepthook = POST_PORTEM_DEBUGGER
działa perfekcyjnie jeśli są zaangażowane żadne nitki. Okazało się, że w przypadku skryptu wielowątkowego mogę używać rpdb dla debuggig pod numerem:
import rpdb; rpdb.set_trace()
To działa doskonale na określonym przerwania ale chcę debugowania wielowątkowego skrypt pośmiertnie (po uncatched wyjątkiem jest podniesiony ). Kiedy próbuję użyć rpdb w funkcji POST_PORTEM_DEBUGGER przy zastosowaniu wielowątkowego dostaję następujący:
Exception in thread Thread-1:
Traceback (most recent call last):
File "/usr/lib/python2.7/threading.py", line 552, in __bootstrap_inner
self.run()
File "./demo.py", line 49, in run
sys.excepthook(*sys.exc_info())
File "./demo.py", line 22, in POST_PORTEM_DEBUGGER
pdb.pm()
File "/usr/lib/python2.7/pdb.py", line 1270, in pm
post_mortem(sys.last_traceback)
AttributeError: 'module' object has no attribute 'last_traceback'
I wygląda
sys.excepthook(*sys.exc_info())
nie założyć wszystko co robi komenda raise
. Chcę tego samego zachowania, jeśli wyjątek jest podniesiony w main(), nawet pod uruchomionym wątku.
Dzięki za cynk. Kończy się jednak wyjątkiem ValeError ('t is None'). Wygląda na to, że wywołanie 'sys.excepthook (* sys.exc_info())' nie ustawia, co robi 'raise'. –