Resposta curta: pyrasite
pip install pyrasite
echo 0 | sudo tee /proc/sys/kernel/yama/ptrace_scope
pyrasite $PID dump_stacks.py
pyrasite-shell <pid>
Contexto Link to heading
Esses dias estava com um bug intermitente que só ocorria no servidor de desenvolvimento, então não estava conseguindo reproduzir localmente.
Tentando descobrir o problema, dei SSH para o servidor e vi que num processo estava justamente acontecendo o que eu queria corrigir.
Então comecei a tentar debugar o código que já estava em execução, sem ter que recomeçar o processo, pois se fizesse isso provavelmente o bug não iria ocorrer.
Foi assim que descobri o pyrasite e como debugar um processo Python que já está em execução.
Pyrasite Link to heading
Com o pyrasite conseguimos injetar código em um processo Python e debugar em tempo de execução.
Fonte: http://pyrasite.com/
Instalação Link to heading
pip install pyrasite
Habilitar o trace Link to heading
No Linux, por uma questão de segurança, o trace é desabilitado por padrão. Então temos que habilitar para conseguir debugar com o pyrasite.
echo 0 | sudo tee /proc/sys/kernel/yama/ptrace_scope
Recomendo voltar o ptrace_scope para o valor padrão (1) após o debug.
Mais informações sobre o ptrace_scope na documentação do Kernel.
Utilização Link to heading
Para utilizar o pyrasite chamamos com o ID do Processo (PID) e o script que queremos executar:
pyrasite $PID my_script.py
A ferramenta já vem com alguns scripts prontos para injetar no processo, são eles:
- dump_stacks.py: printa o stacktrace do código executado
- dump_modules.py: printa os módulos carregados (sys.modules)
- force_garbage_collection.py: força a execução do garbage collector
- helloworld.py: printa Hello World
dump_memory.py: depende de uma lib que não suporta Python 3
Além desses, também temos reverse_python_shell.py, reverse_shell.py, start_callgraph.py, stop_callgraph.py, mas esses eu não consegui usar e não fui muito a fundo.
Para, por exemplo, utilizar o dump_stacks.py, rodamos:
pyrasite $PID dump_stacks.py
Shell Link to heading
Além de executar scripts, também podemos habilitar um shell Python para depurar o que está acontecendo na aplicação. Com o shell conseguimos rodar comandos, acessar variáveis e tudo mais que fazemos num console Python
pyrasite-shell $PID
Troubleshooting Link to heading
- Rodei o pyrasite e não apareceu nenhum resultado
- O output do código injetado aparecerá no stdout do processo principal que está recebendo a injeção. Se o seu processo redireciona o stdout para um arquivo, a saída do código injetado também irá para o mesmo arquivo.