代码之家  ›  专栏  ›  技术社区  ›  Imran

显示运行中Python应用程序的堆栈跟踪

  •  313
  • Imran  · 技术社区  · 17 年前

    我有一个Python应用程序,它有时会卡住,我不知道在哪里。

    是否有任何方法向Python解释器发送信号,向您显示正在运行的确切代码?

    某种即时跟踪?

    相关问题:

    25 回复  |  直到 9 年前
        1
  •  335
  •   Mike Morearty NiCk Newman    11 年前

    import code, traceback, signal
    
    def debug(sig, frame):
        """Interrupt running process, and provide a python prompt for
        interactive debugging."""
        d={'_frame':frame}         # Allow access to frame object.
        d.update(frame.f_globals)  # Unless shadowed by global
        d.update(frame.f_locals)
    
        i = code.InteractiveConsole(d)
        message  = "Signal received : entering python shell.\nTraceback:\n"
        message += ''.join(traceback.format_stack(frame))
        i.interact(message)
    
    def listen():
        signal.signal(signal.SIGUSR1, debug)  # Register handler
    

    要使用它,只需在程序启动时调用listen()函数(您甚至可以将它粘贴到site.py中,让所有python程序都使用它),然后让它运行。在任何时候,都可以使用kill或python向进程发送SIGUSR1信号:

        os.kill(pid, signal.SIGUSR1)
    

    我有另一个脚本做同样的事情,除了它通过管道与正在运行的进程通信(允许调试后台进程等)。在这里发布有点大,但我添加了它作为一个 python cookbook recipe .

        2
  •  151
  •   Demitri    5 年前

    安装信号处理器的建议很好,我经常使用它。例如 bzr pdb.set_trace() 让你立刻陷入困境 pdb 促使(见 bzrlib.breakin 使用pdb,您不仅可以获得当前堆栈跟踪(使用 (w)here 命令),但也检查变量等。

    http://svn.python.org/projects/python/trunk/Misc/gdbinit 在里面 ~/.gdbinit

    • 附上gdb: gdb -p PID
    • 获取python堆栈跟踪: pystack

    最后,附上 strace 可以经常给你一个好主意,一个过程正在做什么。

        3
  •  79
  •   David Foster Eryk Sun    5 年前

    this blog :

    import threading, sys, traceback
    
    def dumpstacks(signal, frame):
        id2name = dict([(th.ident, th.name) for th in threading.enumerate()])
        code = []
        for threadId, stack in sys._current_frames().items():
            code.append("\n# Thread: %s(%d)" % (id2name.get(threadId,""), threadId))
            for filename, lineno, name, line in traceback.extract_stack(stack):
                code.append('File: "%s", line %d, in %s' % (filename, lineno, name))
                if line:
                    code.append("  %s" % (line.strip()))
        print("\n".join(code))
    
    import signal
    signal.signal(signal.SIGQUIT, dumpstacks)
    
        4
  •  57
  •   Nickolay    11 年前

    获取一个对象的堆栈跟踪 措手不及 python程序,在一个股票python中运行 可以用 pyrasite

    $ sudo pip install pyrasite
    $ echo 0 | sudo tee /proc/sys/kernel/yama/ptrace_scope
    $ sudo pyrasite 16262 dump_stacks.py # dumps stacks to stdout/stderr of the python program
    

        5
  •  37
  •   Torsten Marek    17 年前
    >>> import traceback
    >>> def x():
    >>>    print traceback.extract_stack()
    
    >>> x()
    [('<stdin>', 1, '<module>', None), ('<stdin>', 2, 'x', None)]
    

    docs .

    编辑 :如@Douglas Leeder所建议的,要模拟Java的行为,请添加以下内容:

    import signal
    import traceback
    
    signal.signal(signal.SIGUSR1, lambda sig, stack: traceback.print_stack(stack))
    

    添加到应用程序中的启动代码。然后,您可以通过发送 SIGUSR1

        6
  •  30
  •   gulgi    7 年前

    这个 traceback 模块有一些很好的功能,其中包括:打印堆栈:

    import traceback
    
    traceback.print_stack()
    
        7
  •  24
  •   vstinner    12 年前

    你可以试试这个 faulthandler module . 使用 pip install faulthandler

    import faulthandler, signal
    faulthandler.register(signal.SIGUSR1)
    

    在节目开始时。然后将SIGUSR1发送到您的流程(例如: kill -USR1 42 Read the documentation 查看更多选项(例如:登录到文件)和其他显示回溯的方式。

    该模块现在是Python3.3的一部分。对于Python 2,请参见 http://faulthandler.readthedocs.org/

        8
  •  20
  •   Community Mohan Dere    9 年前

    真正帮助我的是 spiv's tip (如果我有声望的话,我会投赞成票并发表评论)因为我从 Python进程。但直到我死了它才起作用 modified the gdbinit script . 因此:

        9
  •  13
  •   Gustavo Rubio    17 年前

    如果要以交互方式调试代码,应按如下方式运行:

    这告诉python解释器使用模块“pdb”运行脚本,该模块是python调试器,如果您像这样运行,解释器将以交互模式执行,就像GDB一样

        10
  •  12
  •   Community Mohan Dere    9 年前

    我想补充这一点作为对 haridsv's response

    我们中的一些人仍然坚持使用早于2.6的Python版本(Thread.ident需要),因此我让代码在Python 2.5中工作(尽管没有显示线程名称),如下所示:

    import traceback
    import sys
    def dumpstacks(signal, frame):
        code = []
        for threadId, stack in sys._current_frames().items():
                code.append("\n# Thread: %d" % (threadId))
            for filename, lineno, name, line in traceback.extract_stack(stack):
                code.append('File: "%s", line %d, in %s' % (filename, lineno, name))
                if line:
                    code.append("  %s" % (line.strip()))
        print "\n".join(code)
    
    import signal
    signal.signal(signal.SIGQUIT, dumpstacks)
    
        11
  •  11
  •   gps    12 年前

    看一看 faulthandler 模块,在Python 3.3中新增。A. faulthandler backport PyPI上提供了用于Python 2中的。

        12
  •  7
  •   Tim Foster    14 年前

    在Solaris上,可以使用pstack(1),无需对python代码进行任何更改。如。

    # pstack 16000 | grep : | head
    16000: /usr/bin/python2.6 /usr/lib/pkg.depotd --cfg svc:/application/pkg/serv
    [ /usr/lib/python2.6/vendor-packages/cherrypy/process/wspbus.py:282 (_wait) ]
    [ /usr/lib/python2.6/vendor-packages/cherrypy/process/wspbus.py:295 (wait) ]
    [ /usr/lib/python2.6/vendor-packages/cherrypy/process/wspbus.py:242 (block) ]
    [ /usr/lib/python2.6/vendor-packages/cherrypy/_init_.py:249 (quickstart) ]
    [ /usr/lib/pkg.depotd:890 (<module>) ]
    [ /usr/lib/python2.6/threading.py:256 (wait) ]
    [ /usr/lib/python2.6/Queue.py:177 (get) ]
    [ /usr/lib/python2.6/vendor-packages/pkg/server/depot.py:2142 (run) ]
    [ /usr/lib/python2.6/threading.py:477 (run)
    etc.
    
        13
  •  7
  •   saaj    6 年前

    这可以用很好的方法来完成 py-spy Python程序的采样分析器 ,因此它的工作是附加到Python进程并对其调用堆栈进行采样。因此 py-spy dump --pid $SOME_PID 您需要做的就是转储进程中所有线程的调用堆栈 $SOME_PID 过程通常,它需要升级权限(读取目标进程的内存)。

    下面是一个线程化Python应用程序的示例。

    $ sudo py-spy dump --pid 31080
    Process 31080: python3.7 -m chronologer -e production serve -u www-data -m
    Python v3.7.1 (/usr/local/bin/python3.7)
    
    Thread 0x7FEF5E410400 (active): "MainThread"
        _wait (cherrypy/process/wspbus.py:370)
        wait (cherrypy/process/wspbus.py:384)
        block (cherrypy/process/wspbus.py:321)
        start (cherrypy/daemon.py:72)
        serve (chronologer/cli.py:27)
        main (chronologer/cli.py:84)
        <module> (chronologer/__main__.py:5)
        _run_code (runpy.py:85)
        _run_module_as_main (runpy.py:193)
    Thread 0x7FEF55636700 (active): "_TimeoutMonitor"
        run (cherrypy/process/plugins.py:518)
        _bootstrap_inner (threading.py:917)
        _bootstrap (threading.py:885)
    Thread 0x7FEF54B35700 (active): "HTTPServer Thread-2"
        accept (socket.py:212)
        tick (cherrypy/wsgiserver/__init__.py:2075)
        start (cherrypy/wsgiserver/__init__.py:2021)
        _start_http_thread (cherrypy/process/servers.py:217)
        run (threading.py:865)
        _bootstrap_inner (threading.py:917)
        _bootstrap (threading.py:885)
    ...
    Thread 0x7FEF2BFFF700 (idle): "CP Server Thread-10"
        wait (threading.py:296)
        get (queue.py:170)
        run (cherrypy/wsgiserver/__init__.py:1586)
        _bootstrap_inner (threading.py:917)
        _bootstrap (threading.py:885)  
    
        14
  •  6
  •   anatoly techtonik Tony    13 年前

    如果您使用的是Linux系统,请使用 gdb 使用Python调试扩展(可以在 python-dbg python-debuginfo 包装)。它还可以帮助处理多线程应用程序、GUI应用程序和C模块。

    $ gdb -ex r --args python <programname>.py [arguments]
    

    这说明 准备 python <programname>.py <arguments> r 解开它。

    gdb 控制台,按 Ctr+C 并执行:

    (gdb) thread apply all py-list
    

    example session 和更多信息 here here .

        15
  •  6
  •   n611x007 David Dossot    10 年前

    我一直在寻找调试线程的解决方案,多亏了haridsv,我在这里找到了它。我使用了稍微简化的版本,使用了traceback.print_stack():

    import sys, traceback, signal
    import threading
    import os
    
    def dumpstacks(signal, frame):
      id2name = dict((th.ident, th.name) for th in threading.enumerate())
      for threadId, stack in sys._current_frames().items():
        print(id2name[threadId])
        traceback.print_stack(f=stack)
    
    signal.signal(signal.SIGQUIT, dumpstacks)
    
    os.killpg(os.getpgid(0), signal.SIGQUIT)
    

        16
  •  3
  •   Tom Lianza    17 年前

    值得一看 Pydb ,“Python调试器的扩展版本,松散地基于gdb命令集”。它包括信号管理器,可以在发送指定信号时启动调试器。

    2006年夏季的一个代码项目着眼于在一个名为 mpdb .

        17
  •  3
  •   Albert    14 年前

    我拼凑了一些工具,将其连接到一个正在运行的Python进程中,并注入一些代码以获得Python shell。

    https://github.com/albertz/pydbattach

        18
  •  2
  •   Dan Lecocq    12 年前

    pyringe 是一个调试器,可以与运行的python进程、打印堆栈跟踪、变量等交互,而无需任何先验设置。

    虽然我过去经常使用信号处理程序解决方案,但在某些环境中仍然很难重现该问题。

        19
  •  2
  •   Phoenix87    4 年前

    如果您想查看正在运行的Python应用程序,以查看类似fashon的top中的“实时”调用堆栈,您可以使用austin tui( https://github.com/p403n1x87/austin-tui )。您可以从PyPI安装它,例如。

    pipx install austin-tui
    

    https://github.com/p403n1x87/austin ),但您可以使用

    austin-tui -p <pid>
    
        20
  •  1
  •   asmeurer    13 年前

    你可以用 PuDB

    from pudb import set_interrupt_handler; set_interrupt_handler()
    

    当您想要中断时,请使用Ctrl-C。你可以继续 c

        21
  •  1
  •   user7610    8 年前

    我在GDB阵营中使用python扩展。跟随 https://wiki.python.org/moin/DebuggingWithGdb

    1. dnf install gdb python-debuginfo sudo apt-get install gdb python2.7-dbg
    2. gdb python <pid of running process>
    3. py-bt

    也考虑 info threads thread apply all py-bt .

        22
  •  1
  •   jakvb    7 年前

    如何调试任何函数 控制台中 :

    你在哪里 使用pdb.set_trace()

    >>> import pdb
    >>> import my_function
    
    >>> def f():
    ...     pdb.set_trace()
    ...     my_function()
    ... 
    

    然后调用创建的函数:

    >>> f()
    > <stdin>(3)f()
    (Pdb) s
    --Call--
    > <stdin>(1)my_function()
    (Pdb) 
    

        23
  •  1
  •   kmaork    5 年前

    你可以使用 hypno 包,像这样:

    hypno <pid> "import traceback; traceback.print_stack()"
    

    或者,如果您不想将任何内容打印到stdout,或者您无权访问它(例如守护进程),则可以使用 madbg 包,它是一个python调试器,允许您附加到正在运行的python程序,并在当前终端中对其进行调试。它类似于 pyrasite pyringe IPython 对于调试器(这意味着颜色和自动完成)。

    要查看正在运行的程序的堆栈跟踪,可以运行:

    madbg attach <pid>
    

    bt

    免责声明-我写了两个软件包

        24
  •  0
  •   Douglas Leeder    17 年前

    我不知道有什么类似的 java's response to SIGQUIT ,因此您可能必须将其构建到应用程序中。也许您可以在另一个线程中创建一个服务器,它可以在响应某种消息时获取stacktrace?

        25
  •  0
  •   Armin Ronacher    17 年前

    不幸的是,strace通常是“修复”竞争条件的观察者,因此输出在那里也没有用处。

        26
  •  0
  •   Alison R.    14 年前

    使用检查模块。

    进口检验 帮助(检查堆栈)

    堆栈(上下文=1) 返回调用方帧上方堆栈的记录列表。

    我觉得这确实很有帮助。

        27
  •  0
  •   jtatum    11 年前

    import pdb, signal
    signal.signal(signal.SIGINT, lambda sig, frame: pdb.Pdb().set_trace(frame))
    

    如果您花费大量时间调试Python,那么pdb是值得学习的。这个界面有点迟钝,但任何使用过类似工具(如gdb)的人都应该熟悉它。

        28
  •  0
  •   Michal Čihař    11 年前

    如果您需要使用uWSGI执行此操作,它必须 Python Tracebacker 内置的,只需在配置中启用它(编号附在每个工作人员的名称上):

    py-tracebacker=/var/run/uwsgi/pytrace
    

    完成此操作后,只需连接到套接字即可打印回溯:

    uwsgi --connect-and-read /var/run/uwsgi/pytrace1
    
        29
  •  -1
  •   Wayne Lambert    6 年前

    在代码运行的地方,您可以插入这个小片段以查看格式良好的打印堆栈跟踪。它假定您有一个名为 logs

    # DEBUG: START DEBUG -->
    import traceback
    
    with open('logs/stack-trace.log', 'w') as file:
        traceback.print_stack(file=file)
    # DEBUG: END DEBUG --!