Exceções comuns passam pelo mecanismo normal do Python e podem ser registradas com logging ou traceback. Porém, um processo também pode travar em código nativo, sofrer segmentation fault, entrar em deadlock ou permanecer bloqueado por tempo indefinido. O módulo faulthandler no Python foi criado para produzir pilhas mínimas mesmo em situações catastróficas nas quais o interpretador já não consegue executar o tratamento convencional.
Neste guia, você aprenderá a habilitar o módulo, gerar dumps manuais, diagnosticar timeouts, registrar sinais Unix e compreender as pilhas C adicionadas ao Python 3.14. O conteúdo complementa nossos artigos sobre traceback no Python, depuração com pdb, introspecção com inspect e vazamentos de memória.
Quando faulthandler é útil
O módulo atende situações em que uma exceção normal pode nunca ser criada. Exemplos incluem falhas em extensões C, stack overflow, aborts, operações bloqueadas e deadlocks entre threads. Ele instala handlers para sinais fatais como SIGSEGV, SIGFPE, SIGABRT, SIGBUS e SIGILL, dependendo da plataforma.
Como o handler pode executar em um estado instável, sua saída é deliberadamente simples: nomes de arquivos, funções e linhas, com limites de frames e threads. Esse formato sacrifica detalhes para aumentar a chance de produzir algum diagnóstico antes do término do processo.
Habilitar no código
A maneira direta é chamar faulthandler.enable() no início da aplicação.
import faulthandler
faulthandler.enable()Por padrão, a saída vai para sys.stderr e inclui todas as threads. Em serviços persistentes, habilite antes de iniciar workers e bibliotecas que criam threads.
Habilitar pela linha de comando
Quando não é possível alterar o código, use a opção -X faulthandler.
python -X faulthandler app.pyTambém é possível definir a variável de ambiente:
PYTHONFAULTHANDLER=1 python app.pyO modo de desenvolvimento do Python habilita o módulo automaticamente. A opção de linha de comando é especialmente útil para reproduzir falhas em ferramentas de terceiros.
Verificar o estado
is_enabled() informa se o handler fatal está ativo.
import faulthandler
if not faulthandler.is_enabled():
faulthandler.enable()disable() remove os handlers instalados por enable(). Normalmente um serviço mantém o recurso ativo durante toda a execução.
Gerar um dump manual
dump_traceback() imprime a pilha atual de todas as threads sem causar uma falha.
import faulthandler
faulthandler.dump_traceback()Isso ajuda a investigar um processo que parece lento ou bloqueado. Com all_threads=False, somente a thread atual é mostrada.
faulthandler.dump_traceback(all_threads=False)Para diagnósticos de deadlock, a visão de todas as threads costuma ser a informação mais valiosa.
Enviar para um arquivo
O destino deve permanecer aberto enquanto o handler estiver configurado.
import faulthandler
arquivo = open("falhas.log", "a", buffering=1)
faulthandler.enable(file=arquivo, all_threads=True)A documentação oficial de faulthandler alerta que o módulo mantém o descritor de arquivo. Se o arquivo for fechado e o número do descritor for reutilizado, o dump pode acabar em outro destino.
Rotação de logs e descritores
Quando um sistema de rotação substitui o arquivo, chame novamente enable() com o novo objeto. O mesmo cuidado vale para dump_traceback_later() e register().
def reabrir_log():
global arquivo
arquivo.close()
arquivo = open("falhas.log", "a", buffering=1)
faulthandler.enable(file=arquivo, all_threads=True)Não dependa apenas de handlers de alto nível que trocam arquivos silenciosamente. Verifique como o processo é reiniciado ou notificado após a rotação.
Diagnosticar timeouts
dump_traceback_later() agenda um dump após determinado número de segundos.
faulthandler.dump_traceback_later(
30,
repeat=False,
)Se a operação terminar antes do prazo, cancele:
try:
executar_operacao_longa()
finally:
faulthandler.cancel_dump_traceback_later()Esse padrão identifica testes congelados, chamadas nativas bloqueadas e deadlocks que não produzem exceção.
Dumps repetidos
Com repeat=True, o módulo gera pilhas periodicamente.
faulthandler.dump_traceback_later(
60,
repeat=True,
)Dumps repetidos mostram se as threads permanecem exatamente nos mesmos frames ou continuam avançando lentamente. Cancele o timer ao concluir o diagnóstico para evitar crescimento desnecessário do log.
Encerrar depois do timeout
O argumento exit=True chama _exit(1) após gerar o dump.
faulthandler.dump_traceback_later(
120,
exit=True,
)_exit() encerra imediatamente, sem executar blocos finally, handlers de atexit ou flush normal de buffers. Use somente quando continuar executando seria pior que uma parada abrupta e quando um supervisor reiniciará o processo.
Diagnóstico sob demanda com sinais
Em sistemas Unix, register() associa um sinal de usuário à geração de pilhas.
import signal
faulthandler.register(
signal.SIGUSR1,
all_threads=True,
)Depois, outro terminal pode solicitar o dump sem interromper o serviço:
kill -USR1 PID_DO_PROCESSOA documentação oficial de signal ajuda a escolher sinais e entender diferenças de plataforma. Esse recurso não está disponível no Windows.
chain=True
Se já existe um handler para o sinal, chain=True chama o handler anterior depois do dump.
faulthandler.register(
signal.SIGUSR1,
all_threads=True,
chain=True,
)Use com cautela, pois o handler anterior pode encerrar o processo ou executar uma ação incompatível. unregister() remove o registro instalado.
Pilha C no Python 3.14
O Python 3.14 adicionou dump_c_stack() e a opção c_stack em enable(). Quando a compilação e o sistema operacional oferecem suporte, o relatório inclui frames nativos além da pilha Python.
faulthandler.enable(c_stack=True)
faulthandler.dump_c_stack()Essa informação é valiosa em extensões C, bibliotecas de ciência de dados, drivers e bindings. Porém, símbolos podem estar ausentes e o dump pode ser lento dependendo das informações DWARF do binário.
Compatibilidade da pilha C
Nem toda plataforma fornece backtrace(), dladdr1() ou suporte adequado no compilador. Nesses casos, o módulo imprime um erro no lugar da pilha C. Trate esse resultado como limitação do ambiente, não como falha da aplicação.
GIL desabilitado
No Python 3.14, quando o GIL está desabilitado, o handler fatal mostra somente a thread atual para reduzir risco de data races. Portanto, a configuração all_threads=True pode produzir um resultado diferente em builds free-threaded.
Registre a versão, o tipo de build e a plataforma junto do dump. Sem essas informações, comparar relatórios entre servidores pode gerar conclusões erradas.
Limitações da saída
O módulo utiliza operações seguras para sinais e não pode depender de alocação normal. A saída aceita somente ASCII com substituição de caracteres, limita strings a 500 caracteres, mostra no máximo 100 frames e 100 threads e não inclui a linha completa do código.
A ordem também é invertida em relação ao traceback normal: a chamada mais recente aparece primeiro. Treine a equipe para ler esse formato.
Testes automatizados
Use o watchdog em testes que podem congelar.
def test_processamento():
faulthandler.dump_traceback_later(10)
try:
resultado = processar_lote()
assert resultado.ok
finally:
faulthandler.cancel_dump_traceback_later()Evite prazos excessivamente curtos em integração contínua, onde a máquina pode estar sobrecarregada. O objetivo é diagnosticar um bloqueio real, não transformar lentidão ocasional em ruído.
Containers e serviços
Em containers, mantenha stderr conectado ao coletor de logs ou use um arquivo persistente. Verifique limites de tamanho, rotação e retenção. Um dump de muitas threads pode ser grande, embora o módulo imponha limites.
Em Kubernetes ou systemd, combine exit=True com políticas de reinício apenas após validar que o serviço é idempotente e que operações interrompidas podem ser retomadas com segurança.
Segurança operacional
Os dumps normalmente não exibem variáveis locais, mas revelam caminhos, funções, arquitetura interna e atividade das threads. Restrinja acesso aos logs e evite publicá-los em respostas HTTP.
Não provoque segmentation faults deliberadamente em produção para testar a configuração. Valide o comportamento em um processo isolado, container de teste ou ambiente de homologação.
faulthandler versus traceback
traceback é mais rico para exceções normais e permite formatação, cadeias e dados estruturados. faulthandler é minimalista e continua útil quando o processo está travado ou sofreu uma falha nativa. Em uma aplicação madura, os dois módulos se complementam.
faulthandler versus pdb
pdb permite pausar, inspecionar variáveis e avançar pelo código. Ele exige um processo suficientemente saudável e interação. faulthandler produz um snapshot passivo, adequado a ambientes sem terminal ou a falhas que derrubam o interpretador.
Erros frequentes
- Fechar o arquivo usado pelo handler.
- Rotacionar logs sem reconfigurar o descritor.
- Esquecer de cancelar um dump agendado.
- Usar
exit=Truesem supervisor ou recuperação. - Esperar variáveis locais e código-fonte completo.
- Ignorar diferenças entre Unix e Windows.
- Tratar ausência da pilha C como erro do programa.
- Expor dumps publicamente.
Boas práticas
- Habilite no início do processo.
- Direcione a saída para um destino persistente.
- Reabra o handler após rotação de logs.
- Use timeouts em testes e operações críticas.
- Registre um sinal de diagnóstico em Unix.
- Documente versão, build e sistema operacional.
- Combine com logging, traceback e métricas.
- Proteja e retenha os dumps de acordo com a política de segurança.
Conclusão
O módulo faulthandler no Python fornece um último recurso de observabilidade para crashes, deadlocks, timeouts e falhas em código nativo. Ele pode ser ativado no código, por variável de ambiente ou pela opção -X, além de gerar dumps manuais, programados ou acionados por sinais.
Seu valor vem justamente da simplicidade. Mesmo sem variáveis locais ou formatação detalhada, uma lista de threads e frames pode revelar o lock, a extensão ou a função em que o processo parou. Com descritores de arquivo bem administrados, limites operacionais e integração com supervisores, faulthandler transforma travamentos silenciosos em diagnósticos acionáveis.







