O módulo sys.monitoring oferece uma forma moderna de observar a execução de programas Python com baixo overhead. Introduzido para atender ferramentas como depuradores, profilers, rastreadores de cobertura e sistemas de observabilidade, ele permite registrar callbacks para eventos específicos sem depender exclusivamente de sys.settrace. Isso torna a instrumentação mais seletiva, previsível e adequada para ambientes reais.
Neste guia, você aprenderá como o modelo de ferramentas funciona, quais eventos podem ser monitorados, como ativar callbacks, como reduzir impacto de desempenho e como estruturar uma camada de observabilidade segura.
Por que usar sys.monitoring?
A instrumentação tradicional com sys.settrace costuma executar uma função de callback para muitos eventos, mesmo quando a ferramenta precisa observar apenas uma parte do programa. Em aplicações grandes, isso pode gerar custo elevado. sys.monitoring resolve esse problema permitindo selecionar eventos específicos e habilitá-los globalmente ou por código.
Entre os casos de uso estão medição de cobertura, depuração, detecção de chamadas, análise de retorno, rastreamento de exceções e criação de ferramentas de desenvolvimento. A API foi pensada para permitir coexistência entre ferramentas independentes, cada uma com seu identificador.
Identificadores de ferramenta
Antes de registrar eventos, uma ferramenta deve reservar um ID. Esse ID separa callbacks e configurações de diferentes consumidores. O fluxo típico envolve escolher um identificador, associá-lo a um nome legível e liberar o recurso quando a ferramenta terminar.
import sys
TOOL_ID = 3
sys.monitoring.use_tool_id(TOOL_ID, "meu-monitor")
try:
pass
finally:
sys.monitoring.free_tool_id(TOOL_ID)
Esse cuidado evita colisões e torna o ciclo de vida explícito. Em bibliotecas, prefira encapsular essa lógica em um context manager ou classe responsável pelo monitoramento.
Eventos disponíveis
A API organiza eventos em constantes. Dependendo da versão do Python, você pode observar início de execução, retorno, chamada, salto, instruções, exceções e outros pontos. A seleção deve ser mínima: ative somente o que sua ferramenta realmente precisa.
events = sys.monitoring.events
mask = events.PY_START | events.PY_RETURN
sys.monitoring.set_events(TOOL_ID, mask)
Uma máscara de bits combina vários eventos. Isso facilita habilitar e desabilitar grupos de sinais de forma eficiente.
Registrando callbacks
Callbacks são registrados por evento. A assinatura depende do tipo de evento, portanto consulte a documentação da versão utilizada. Um callback simples pode registrar o objeto de código e o deslocamento da instrução.
def on_start(code, instruction_offset):
print("início:", code.co_name, instruction_offset)
sys.monitoring.register_callback(
TOOL_ID,
sys.monitoring.events.PY_START,
on_start,
)
Evite realizar operações pesadas dentro do callback. A função pode ser chamada muitas vezes, então prefira acumular contadores, enviar dados para uma fila ou registrar estruturas compactas para processamento posterior.
Monitoramento global e local
O monitoramento global aplica eventos à execução de forma ampla. Já o monitoramento local permite escolher objetos de código específicos. Essa distinção é essencial para reduzir overhead.
Em um profiler interno, por exemplo, você pode habilitar eventos apenas para módulos da aplicação, ignorando bibliotecas externas. Em testes, pode limitar a observação a funções críticas. Quanto menor a superfície monitorada, menor o impacto.
Exemplo de contador de chamadas
import sys
from collections import Counter
TOOL_ID = 3
calls = Counter()
def on_start(code, instruction_offset):
calls[code.co_name] += 1
sys.monitoring.use_tool_id(TOOL_ID, "contador")
sys.monitoring.register_callback(
TOOL_ID,
sys.monitoring.events.PY_START,
on_start,
)
sys.monitoring.set_events(
TOOL_ID,
sys.monitoring.events.PY_START,
)
# execute a aplicação aqui
sys.monitoring.set_events(TOOL_ID, 0)
sys.monitoring.free_tool_id(TOOL_ID)
print(calls)
Esse exemplo é propositalmente simples. Em produção, garanta limpeza mesmo em caso de exceção e evite imprimir diretamente no callback.
Boas práticas de desempenho
Primeiro, ative o menor número possível de eventos. Segundo, mantenha callbacks curtos. Terceiro, filtre módulos, arquivos ou objetos de código. Quarto, processe dados fora do caminho crítico. Quinto, ofereça uma chave de configuração para desligar a instrumentação.
Também vale medir o próprio monitor. Compare tempo e uso de CPU com a ferramenta ligada e desligada. Uma solução de observabilidade que altera significativamente o comportamento da aplicação pode produzir dados enganosos.
Tratamento de erros
Callbacks não devem interromper a aplicação monitorada. Capture exceções internas, registre falhas de forma controlada e desative a ferramenta se ela entrar em estado inconsistente. Evite recursão acidental: um callback que executa código monitorado pode gerar mais eventos.
Uma estratégia segura é manter uma flag thread-local ou por contexto para impedir reentrada. Também é importante proteger estruturas compartilhadas quando múltiplas threads estiverem em execução.
Integração com logs e métricas
Em vez de escrever um log para cada evento, agregue dados. Conte chamadas, calcule duração por função, registre amostras ou envie lotes. Para logs estruturados, associe nome do módulo, função, arquivo e linha. Para métricas, use contadores e histogramas.
Quando a aplicação usa asyncio, combine a instrumentação com contexto de requisição. O artigo sobre contextvars no Python mostra como preservar contexto em tarefas assíncronas. Para entender execução assíncrona, veja também asyncio.Runner no Python.
Testando a ferramenta
Crie testes para funções normais, métodos, generators, corrotinas e exceções. Verifique que eventos esperados são registrados, que a ferramenta é desativada corretamente e que não há vazamento de callbacks entre testes.
Use funções pequenas e determinísticas. Também teste concorrência e reentrada. Compare os resultados com expectativas explícitas em vez de depender apenas de logs visuais.
Compatibilidade de versão
sys.monitoring não existe em versões antigas do Python. Uma biblioteca reutilizável deve detectar a disponibilidade da API e oferecer fallback. Você pode usar hasattr(sys, "monitoring") e, quando necessário, recorrer a outra estratégia.
Consulte a documentação oficial de sys.monitoring e a PEP 669 para entender o desenho da API. Para introspecção adicional, veja inspect.signature no Python e inspect.getmembers_static no Python.
Arquitetura recomendada
Uma implementação robusta pode ser dividida em quatro partes: configuração, callbacks, armazenamento e exportação. A configuração escolhe eventos e filtros. Os callbacks coletam dados mínimos. O armazenamento agrega em memória. A exportação envia resultados para logs, métricas ou arquivos.
Essa separação facilita testes, reduz acoplamento e permite trocar o destino dos dados sem alterar a instrumentação.
Quando não usar
Não use monitoramento detalhado permanentemente sem medir o custo. Não use callbacks para lógica de negócio. Não dependa da ordem exata de eventos como contrato da aplicação. E não exponha dados sensíveis coletados de nomes, caminhos ou exceções sem filtragem.
Conclusão
sys.monitoring oferece uma base eficiente para ferramentas de observabilidade em Python. O principal benefício está na seleção fina de eventos e na possibilidade de monitoramento local. Com callbacks curtos, filtros claros, limpeza garantida e testes de overhead, é possível criar depuradores, profilers e analisadores úteis sem comprometer a aplicação.







