source

실행 중인 Python 응용 프로그램의 스택 추적 표시

nicesource 2023. 1. 19. 07:04
반응형

실행 중인 Python 응용 프로그램의 스택 추적 표시

Python 어플리케이션이 가끔 멈춰서 어디에 있는지 모르겠어요.

Python 인터프리터에게 실행 중인 정확한 코드를 표시하도록 신호를 보낼 수 있는 방법이 있습니까?

즉석 추적 같은 거요?

관련 질문:

저는 이런 경우에 사용하는 모듈을 가지고 있습니다.프로세스가 장시간 실행되지만 불분명하고 재현할 수 없는 이유로 인해 중단되는 경우가 있습니다.약간 해킹이 심하고 unix에서만 작동합니다(신호 필요).

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() 함수를 호출하면 됩니다(모든 python 프로그램에서 사용할 수 있도록 site.py에 삽입할 수도 있습니다).언제든지 kill 또는 python을 사용하여 프로세스에 SIGUSR1 신호를 전송합니다.

    os.kill(pid, signal.SIGUSR1)

이로 인해 프로그램은 현재 위치에서 파이썬 콘솔로 전환되어 스택트레이스를 표시하고 변수를 조작할 수 있게 됩니다.실행을 계속하려면 control-d(EOF)를 사용합니다(단, 신호를 보내는 시점에서 I/O 등이 중단되므로 완전히 간섭하지 않습니다).

동일한 작업을 수행하는 다른 스크립트가 있지만 파이프를 통해 실행 중인 프로세스와 통신합니다(백그라운드 프로세스 디버깅 등).여기에 올리기에는 조금 큰 편이지만, Python 요리책 레시피로 추가했습니다.

신호 핸들러를 설치하는 것은 좋은 제안이며, 자주 사용하고 있습니다.예를 들어, bzr은 디폴트로 SIGQUIT 핸들러를 인스톨 합니다.이 핸들러는,pdb.set_trace()즉시 pdb 프롬프트로 이동합니다.(정확한 자세한 내용은 bzrlib.breakin 모듈의 소스를 참조하십시오).pdb에서는 현재 스택트레이스를 취득할 수 있을 뿐만 아니라(w)here변수

다만, 신호 핸들러를 인스톨 할 수 없었던 프로세스를 디버깅 할 필요가 있는 경우가 있습니다.Linux 에서는 gdb를 프로세스에 연결하여 gdb 매크로를 사용하여 python 스택트레이스를 취득할 수 있습니다.http://svn.python.org/projects/python/trunk/Misc/gdbinit 를 에 삽입하다~/.gdbinit 그럼아니다,아니다,아니다,아니다,아니다,아니다.

  • gdb: 를 합니다.gdb -p PID
  • python 을 가져옵니다.pystack

유감스럽게도 완전히 신뢰할 수 있는 것은 아니지만, 대부분의 경우 효과가 있습니다.https://wiki.python.org/moin/DebuggingWithGdb 도 참조해 주세요.

「」, 「」를 붙입니다.strace프로세스가 어떤 역할을 하는지 잘 알 수 있는 경우가 많습니다.

저는 거의 항상 여러 스레드를 취급하고 있고 메인 스레드는 일반적으로 그다지 많은 작업을 하지 않기 때문에 가장 흥미로운 것은 모든 스택을 덤프하는 것입니다(Java의 덤프에 가깝습니다).다음은 이 블로그를 기반으로 한 구현입니다.

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)

준비되지 않은 python 프로그램의 스택 트레이스를 가져오고, 기호를 디버깅하지 않고 stock python에서 실행할 수 있습니다.Ubuntu Trusty에서 마법처럼 작동했습니다.

$ 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

(@Albert에 대한 힌트입니다.이 답변에는 다른 툴 중에서도 포인터가 포함되어 있습니다.)

>>> import traceback
>>> def x():
>>>    print traceback.extract_stack()

>>> x()
[('<stdin>', 1, '<module>', None), ('<stdin>', 2, 'x', None)]

스택 트레이스를 적절히 포맷할 수도 있습니다.문서도 참조해 주세요.

편집: @Douglas Leeder의 제안대로 Java의 동작을 시뮬레이트하려면 다음과 같이 추가합니다.

import signal
import traceback

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

응용 프로그램의 시작 코드로 이동합니다. 후 스택을 하려면 , 「다음에」를 송신해 .SIGUSR1파이썬

트레이스백 모듈에는 print_stack 등의 기능이 있습니다.

import traceback

traceback.print_stack()

폴탄들러 모듈을 시험해 볼 수 있습니다.를 사용하여 설치하다pip install faulthandler★★★★

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

프로그램을 시작할 때 사용합니다.SIGUSR1을 「SIGUSR1」 「SIGUSR1」 「SIGUSR1」 「SIGUSR1 「SIGUSR1」 「SIGUSR1」 「SIGUSR1」 「SIGUSR1」 「SIGUSR1」).kill -USR1 42)는 표준 출력에 대한 모든 스레드의 Python 트레이스백을 표시합니다.기타 옵션(예: 파일에 로그인) 및 트레이스백을 표시하는 기타 방법에 대해서는 설명서를 참조하십시오.

모듈은 이제 Python 3.3의 일부가 되었습니다.Python 2 의 경우는, http://faulthandler.readthedocs.org/ 를 참조해 주세요.

여기서 정말 도움이 된 것은 준비되지 않은 Python 프로세스에서 스택 트레이스를 얻을 수 있는 spiv의 팁(평판 포인트가 있으면 투표해서 코멘트하겠습니다)입니다.하지만 gdbinit 스크립트를 수정하기 전까지는 작동되지 않았습니다.그래서:

  • https://svn.python.org/projects/python/trunk/Misc/gdbinit을 다운로드하여 에 넣습니다.~/.gdbinit

  • 편집, [edit: no needed; 2010-01-14 현재 링크된 파일에는 이미 이 변경이 있습니다]로 변경합니다.

  • gdb: 를 합니다.gdb -p PID

  • python 을 가져옵니다.pystack

python -dv yourscript.화이

그러면 인터프리터가 디버깅모드로 동작하고 인터프리터의 동작 트레이스가 표시됩니다.

코드를 대화식으로 디버깅하려면 다음과 같이 실행해야 합니다.

python -m pdb yourscript.화이

이는 Python 인터프리터가 Python 디버거인 모듈 "pdb"를 사용하여 스크립트를 실행하도록 지시합니다. 만약 인터프리터가 GDB와 마찬가지로 인터프리터가 인터랙티브 모드로 실행되도록 합니다.

haridsv의 답변에 코멘트로 추가하고 싶지만 그렇게 할 만한 평판이 없습니다.

일부는 여전히 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)

Python 3.3의 새로운 모듈을 살펴보세요.Python 2에서 사용하는 백포트는 PyPI에서 사용할 수 있습니다.

그것은 훌륭한 파이 스파이로 할 수 있다.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)  

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.

시스템을 Linux의 기능을 합니다.gdb 디버깅 기능 포함 디버깅 확장 기능 )python-dbg ★★★★★★★★★★★★★★★★★」python-debuginfo 및 C에도 도움이 .또한 멀티스레드 애플리케이션, GUI 애플리케이션 및 C 모듈에도 도움이 됩니다.

프로그램 실행 방법:

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

이 지시하는 것입니다.gdbpython <programname>.py <arguments> ★★★★★★★★★★★★★★★★★」r

행업할 때는, 「」로 .gdb콘솔, 누름 및 실행:

(gdb) thread apply all py-list

세션 예시와 자세한 내용이쪽과 이쪽을 참조해 주세요.

스레드를 디버깅하기 위한 솔루션을 찾고 있었는데 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)

필요에 따라 스레드도 이름으로 필터링합니다.

실행 중인 Python 프로세스에 접속하여 Python 쉘을 얻기 위해 코드를 주입하는 툴을 해킹했습니다.

여기를 참조해 주세요.https://github.com/albertz/pydbattach

Pydb는 "gdb 명령어 세트를 기반으로 한 파이썬 디버거의 확장 버전"으로 볼 만하다.여기에는 지정된 신호가 전송될 때 디버거를 시작할 수 있는 신호 관리자가 포함됩니다.

2006년 Summer of Code 프로젝트에서는 mpdb라는 모듈의 pydb에 원격 디버깅 기능을 추가하는 것을 검토했습니다.

3로는 Austin 3.3을 할 수 .부터는-w/--where옵션을 지정하여 현재 스택트레이스를 내보냅니다https://stackoverflow.com/a/70905181/1838793 를 참조해 주세요.

여기에 이미지 설명 입력

실행중인 Python 어플리케이션에서 "라이브" 콜 스택을 톱과 같은 패션으로 보고 싶다면 https://github.com/p403n1x87/austin-tui)을 사용할 수 있습니다.예를 들어 PyPI에서 설치할 수 있습니다.

pipx install austin-tui

작동하려면 Austin 바이너리가 필요합니다(https://github.com/p403n1x87/austin),. 단, 실행 중인 Python 프로세스에 접속할 수 있습니다.

austin-tui -p <pid>

pyringe는 python 프로세스 실행, 스택 트레이스, 변수 인쇄 등과 사전 설정 없이 상호작용할 수 있는 디버거입니다.

과거에 신호 핸들러 솔루션을 자주 사용했지만, 특정 환경에서는 여전히 문제를 재현하기 어려울 수 있습니다.

이를 위해 저주 인터페이스를 가진 PuDB, Python 디버거를 사용할 수 있습니다.추가만 하면 됩니다.

from pudb import set_interrupt_handler; set_interrupt_handler()

Ctrl+C를 누릅니다.하다, 하다, 하다, 하다, 이렇게 돼요.c놓치고 다시 시도하고 싶을 때는 여러 번 부러집니다.

나는 파이썬 확장자를 가진 GDB 캠프에 있다.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.

콘솔에서 기능을 디버깅하는 방법:

pdb를 사용하는 함수를 만듭니다.set_debug 명령어를 사용하여 디버깅할 함수를 지정합니다.

>>> import pdb
>>> import my_function

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

그런 다음 생성된 함수를 호출합니다.

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

해피 디버깅 :)

다음과 같이 hypno 패키지를 사용할 수 있습니다.

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

스택 트레이스를 프로그램의 stdout에 인쇄합니다.

또는 stdout에 아무것도 인쇄하지 않거나 액세스 권한이 없는 경우(예를 들어 데몬), 실행 중인 python 프로그램에 연결하여 현재 단말기에서 디버깅할 수 있는 python 디버거인 madbg 패키지를 사용할 수 있습니다.와 비슷하다.pyrasite ★★★★★★★★★★★★★★★★★」pyringe필요 , 「」, 「」, 「」, 「」의 gdb」를 사용합니다IPython디버거의 경우(색상과 자동완성을 의미합니다).

실행 중인 프로그램의 스택트레이스를 표시하려면 다음 작업을 수행합니다.

madbg attach <pid>

셸에 과 같이 bt

면책사항 - 두 패키지 모두 작성했습니다.

SIGQUIT에 대한 Java의 응답과 비슷한 것은 모르기 때문에 어플리케이션에 내장해야 할 수도 있습니다.어떤 종류의 메시지에 응답하여 스택 트레이스를 얻을 수 있는 서버를 다른 스레드에 만들 수 있을까요?

실행 중인 python 프로세스에 접속하여 적절한 결과를 얻을 수 있는 방법은 없습니다.프로세스가 잠긴 경우, 제가 해야 할 일은 스트레이스를 접속하여 정확히 무슨 일이 일어나고 있는지 알아내는 것입니다.

불행히도, 종종 인종 조건을 "수정"하여 생산물이 거기서도 쓸모없도록 하는 관찰자이다.

검사 모듈을 사용합니다.

import inspect help(inspect.stack) 모듈 검사 기능 스택 도움말:

stack(slack=1) 발신자 프레임 위에 있는 스택에 대한 레코드 목록을 반환합니다.

나는 그것이 정말로 도움이 된다고 생각한다.

Python 3에서 pdb는 디버거에서 c(ont(inue))를 처음 사용할 때 신호 핸들러를 자동으로 설치합니다.그 후에 Control-C를 누르면 바로 그곳으로 돌아갑니다.Python 2에서는 비교적 오래된 버전에서도 동작할 수 있는 원라이너가 있습니다(2.7에서 테스트되었습니다만, Python 소스를 2.4로 확인했습니다).

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

pdb는 Python을 디버깅하는 데 많은 시간을 할애한다면 배울 가치가 있습니다.이 인터페이스는 다소 둔하지만 gdb와 같은 유사한 도구를 사용해 본 사람이라면 친숙할 것입니다.

uWSGI를 사용하여 이 작업을 수행해야 하는 경우 Python Tracebacker가 내장되어 있으며 구성 내에서 활성화하기만 하면 됩니다(번호는 각 작업자의 이름에 첨부됩니다).

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

이렇게 하면 소켓에 연결하는 것만으로 백트레이스를 인쇄할 수 있습니다.

uwsgi --connect-and-read /var/run/uwsgi/pytrace1

코드가 실행되는 시점에서 이 작은 스니펫을 삽입하여 올바르게 인쇄된 스택트레이스를 표시할 수 있습니다. 하다라는 합니다.logs프로젝트의 루트 디렉토리로 이동합니다.

# DEBUG: START DEBUG -->
import traceback

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

언급URL : https://stackoverflow.com/questions/132058/showing-the-stack-trace-from-a-running-python-application

반응형