Pergunta

Eu tenho esta aplicação Python que fica preso ao longo do tempo e não consigo descobrir onde.

Existe alguma maneira para sinalizar interpretador Python para mostrar-lhe o código exato que está sendo executado?

Algum tipo de stacktrace on-the-fly?

Perguntas relacionadas:

Foi útil?

Solução

Eu tenho uso I módulo para situações como esta - onde um processo será executado por um longo tempo, mas fica preso às vezes por desconhecido e razões irreproduzíveis. É um pouco hacky, e só funciona em Unix (requer sinais):

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

Para usar, basta chamar a função listen () em algum ponto quando o programa inicia-se (Você pode até mesmo colocá-lo em site.py ter todo python programas de usá-lo), e deixá-lo correr. A qualquer momento, enviar o processo um sinal SIGUSR1, utilizando matar, ou em python:

    os.kill(pid, signal.SIGUSR1)

Isto fará com que o programa para quebrar a um console de python no ponto em que está atualmente em, mostrando-lhe o rastreamento de pilha, e permitindo-lhe manipular as variáveis. Use control-d (EOF) para continuar a executar (embora note que você provavelmente interrupção qualquer I / O etc no ponto em que sinalizar, por isso não é totalmente não-intrusiva.

Eu tenho um outro script que faz a mesma coisa, exceto que ele se comunica com o processo em execução através de um tubo (para permitir a depuração processos backgrounded etc). É um pouco grande para postar aqui, mas eu adicionei-lo como um python livro de receitas receita .

Outras dicas

A sugestão para instalar um manipulador de sinal é boa, e eu usá-lo muito. Por exemplo, bzr por padrão instala um manipulador SIGQUIT que invoca pdb.set_trace() para deixá-lo imediatamente em uma APO pronta. (Veja a bzrlib.breakin < source / a> do módulo para os detalhes exatos.) Com APO você pode não só obter o rastreamento de pilha atual, mas também inspecionar variáveis, etc.

No entanto, às vezes eu preciso para depurar um processo que não têm a previsão para instalar o manipulador de sinal. No Linux, você pode anexar gdb para o processo e obter um rastreamento de pilha python com algumas macros GDB. Coloque http://svn.python.org/projects/python/trunk/Misc/ gdbinit em ~/.gdbinit, então:

  • Anexar gdb: gdb -p PID
  • Obter o rastreamento de pilha python: pystack

Não é totalmente confiável, infelizmente, mas funciona na maioria das vezes.

Finalmente, anexando strace muitas vezes pode lhe dar uma boa idéia do que um processo está fazendo.

Eu estou quase sempre lidar com vários segmentos e segmento principal geralmente não está fazendo muito, então o que é mais interessante é para despejar todas as pilhas (que é mais como despejo do Java). Aqui é uma implementação baseada em neste 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)
>>> import traceback
>>> def x():
>>>    print traceback.extract_stack()

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

Você pode também muito bem formatar o rastreamento de pilha, consulte a docs .

Editar : Para simular o comportamento do Java, como sugerido por @Douglas Leeder, acrescentar o seguinte:

import signal
import traceback

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

para o código de inicialização na sua aplicação. Em seguida, você pode imprimir a pilha enviando SIGUSR1 para o processo de Python em execução.

O traceback módulo tem algumas agradáveis funções, entre elas: print_stack:

import traceback

traceback.print_stack()

Você pode tentar o faulthandler módulo . Instalá-lo usando pip install faulthandler e adicione:

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

no início do seu programa. Em seguida, enviar SIGUSR1 ao seu processo (ex: kill -USR1 42) para exibir o rastreamento Python de todos os segmentos para a saída padrão. Leia o documentação para mais opções (ex: log em um arquivo) e outras formas de mostrar o rastreamento.

O módulo é agora parte do Python 3.3. Para Python 2, consulte http://faulthandler.readthedocs.org/

O que realmente me ajudou aqui é de spiv ponta (que eu votaria-se e comentar sobre se eu tivesse os pontos de reputação) para obter um rastreamento de pilha fora de um despreparados processos Python. Só que não funcionou até que eu modificado o script gdbinit . Assim:

Gostaria de acrescentar isso como um comentário a haridsv de resposta , mas eu não têm a reputação de fazê-lo:

Alguns de nós ainda está preso em uma versão do Python mais velha do que 2.6 (necessário para Thread.ident), então eu tenho o código de trabalho em Python 2.5 (embora sem o nome do thread que está sendo exibido) como tal:

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 -dv yourscript.py

Isso fará com que o interpretador para executar no modo de depuração e para dar-lhe um traço do que o intérprete está fazendo.

Se você quiser depurar interativamente o código que você deve executá-lo como este:

python -m pdb yourscript.py

Isso diz o interpretador Python para executar o script com o módulo "APO", que é o depurador python, se você executá-lo como que o intérprete será executado no modo interativo, bem como GDB

Dê uma olhada na faulthandler módulo novo em Python 3.3 . A faulthandler backport para uso em Python 2 está disponível em PyPI.

No Solaris, você pode usar pstack (1) Não muda para o código python são necessárias. por exemplo.

# 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.

Se você estiver em um sistema Linux, use a grandiosidade de gdb com extensões de depuração Python (pode ser em pacote python-dbg ou python-debuginfo). Ela também ajuda com aplicações de vários segmentos, aplicações GUI e módulos C.

Execute o programa com:

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

Isto instrui gdb para preparar python <programname>.py <arguments> e run-lo.

Agora, quando você programa trava, chave na consola gdb, pressione Ctr + C e executar:

(gdb) thread apply all py-list

exemplo sessão e mais informações aqui e aqui .

Eu estava procurando por um tempo para uma solução para depurar meus tópicos e eu achei aqui graças a haridsv. Eu uso um pouco versão empregando o traceback.print_stack simplificado ():

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)

Para as minhas necessidades Eu também fios de filtro por nome.

pena de olhar para Pydb ", uma versão expandida do depurador Python vagamente baseado no conjunto de comandos gdb". Ele inclui gestores de sinal que pode cuidar de iniciar o depurador quando um sinal especificado é enviado.

A 2006 Summer of Code Project olhou para adicionar recursos remoto depuração para pydb em um módulo chamado de mpdb .

Eu cortei juntos alguma ferramenta que une em um processo e injeta Python executar algum código para obter um shell Python.

Veja aqui: https://github.com/albertz/pydbattach

pyringe é um depurador que pode interagir com a execução de processos pitão, rastreamentos de pilha de impressão, variáveis, etc. sem qualquer configuração a priori.

Embora eu tenha usado frequentemente a solução manipulador de sinal no passado, ele ainda pode muitas vezes ser difícil de reproduzir o problema em determinados ambientes.

Não há nenhuma maneira de ligar para um processo de python em execução e obter resultados razoáveis. O que devo fazer se os processos de trancar é enganchando strace e tentando descobrir o que exatamente está acontecendo.

Infelizmente, muitas vezes strace é o observador que "correções" condições de corrida para que a saída é inútil lá também.

Você pode usar PuDB , um depurador Python com maldições interface para fazer isso. Basta adicionar

from pudb import set_interrupt_handler; set_interrupt_handler()

ao seu código e usar Ctrl-C, quando você quer quebrar. Você pode continuar com c e quebrar novamente várias vezes se você perdê-lo e quer tentar novamente.

Como depurar qualquer função na consola :

Criar função onde uso pdb.set_trace () , em seguida, a função que você deseja depurar.

>>> import pdb
>>> import my_function

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

Função seguida, chamar criado:

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

depuração feliz:)

Eu não sei de qualquer coisa semelhante a resposta de java para SIGQUIT , assim você pode ter que construí-lo na sua aplicação. Talvez você poderia fazer um servidor em outro segmento que pode obter um stacktrace em resposta a uma mensagem de algum tipo?

Utilize o módulo de inspecionar.

importação inspecionar ajuda (inspect.stack) Ajuda na pilha função no módulo inspecionar:

pilha (contexto = 1) Retornar uma lista de registros para a pilha acima do quadro do chamador.

Acho que é muito útil.

Em Python 3, pdb irá instalar automaticamente um manipulador de sinal a primeira vez que você usar c (ont (inue)) no depurador. Pressionar Control-C depois vai deixá-lo de volta para lá. Em Python 2, aqui está uma frase que deve funcionar mesmo em versões relativamente antigas (testados em 2,7, mas eu verifiquei Python fonte de volta para 2,4 e parecia tudo bem):

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

APO vale a pena aprender se você gastar qualquer quantidade de tempo de depuração Python. A interface é um pouco obtuso, mas deve ser familiar para qualquer um que usou ferramentas semelhantes, como gdb.

No caso de você precisar fazer isso com uWSGI, tem Python Tracebacker built-in e é apenas questão de permitindo-na configuração (número é anexado ao nome para cada trabalhador):

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

Depois de ter feito isso, você pode imprimir backtrace simplesmente conectando ao socket:

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

Estou no acampamento GDB com as extensões python. Siga https://wiki.python.org/moin/DebuggingWithGdb , o que significa

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

Considere também info threads e thread apply all py-bt.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top