事后调试多线程脚本

时间:2014-04-18 13:08:09

标签: python multithreading debugging pdb

我正在尝试调试多线程脚本。一旦例外是 提出我想:

  1. 向监控系统报告(仅在以下示例中打印)
  2. 停止整个脚本(包括所有其他线程)
  3. 在透视引发异常中调用post mortem调试器提示
  4. 我准备了非常复杂的例子来说明我是如何解决它的:

    #!/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()
    

    的诀窍
    sys.excepthook = POST_PORTEM_DEBUGGER
    
    如果不涉及任何线程,

    完美地工作。我发现如果是的话 多线程脚本我可以通过调用:

    rpdb用于debuggig
    import rpdb; rpdb.set_trace()
    

    它适用于定义的断点,但我想调试 多线程脚本post mortem(在未捕获的异常之后) 提高)。当我尝试在POST_PORTEM_DEBUGGER函数中使用rpdb时 多线程应用程序我得到以下:

    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'
    

    我看起来像

    sys.excepthook(*sys.exc_info())
    

    没有设置raise命令的全部内容。 如果在main()中引发异常,我想要相同的行为 在启动线程下。

2 个答案:

答案 0 :(得分:0)

(我没有测试过我的答案,但在我看来......)

pdb.pm(pm =“post mortem”)的调用失败只是因为之前没有“死亡”。即该程序仍在运行。

查看pdb源代码,您会发现pdb.pm的实现:

def pm():
    post_mortem(sys.last_traceback)

这让我觉得你真正想要做的就是调用pdb.post_mortem()而没有args。看起来默认行为完全符合您的需要。

更多源代码(注意t = sys.exc_info()[2]行):

def post_mortem(t=None):
    # handling the default
    if t is None:
        # sys.exc_info() returns (type, value, traceback) if an exception is
        # being handled, otherwise it returns None
        t = sys.exc_info()[2]
        if t is None:
            raise ValueError("A valid traceback must be passed if no "
                                               "exception is being handled")

    p = Pdb()
    p.reset()
    p.interaction(None, t)

答案 1 :(得分:0)

这可以提供帮助:

import sys
from IPython.core import ultratb

sys.excepthook = ultratb.FormattedTB(mode='Verbose', color_scheme='Linux',
    call_pdb=True, ostream=sys.__stdout__)