sys.monitoring: instrumentación de bajo overhead

Publicado el: 03/09/2026
Tempo de leitura: 6 minutos
Monitoreo de rendimiento y ejecución de código Python

sys.monitoring es la API moderna de Python para observar la ejecución de programas con menor overhead y más control que el tracing tradicional. Está diseñada para depuradores, profilers, herramientas de cobertura, analizadores de rendimiento y sistemas de observabilidad que necesitan eventos concretos sin recibir todas las notificaciones posibles.

En esta guía aprenderás a reservar un identificador de herramienta, seleccionar eventos, registrar callbacks, limitar el monitoreo a código específico, reducir impacto, evitar recursión y diseñar una arquitectura segura para producción.

Por qué usar sys.monitoring

El tracing clásico mediante sys.settrace puede ser costoso porque el callback se ejecuta para muchos eventos. Una herramienta que solo necesita detectar el inicio y el retorno de funciones termina pagando por una superficie más amplia. sys.monitoring permite activar únicamente los eventos útiles y, cuando corresponde, solo para determinados objetos de código.

Esto resulta útil para cobertura, depuración, conteo de llamadas, análisis de excepciones, diagnóstico en runtime y herramientas de desarrollo. Varias herramientas pueden coexistir gracias a identificadores separados.

Reservar un identificador

Cada consumidor debe reservar un ID y asociarlo con un nombre legible. El ID separa callbacks y configuraciones de otros monitores.

import sys

TOOL_ID = 3
sys.monitoring.use_tool_id(TOOL_ID, "mi-monitor")

try:
    pass
finally:
    sys.monitoring.free_tool_id(TOOL_ID)

Libera siempre el identificador. Un context manager o una clase dedicada ayuda a garantizar limpieza incluso cuando ocurre una excepción.

Seleccionar eventos

La API expone constantes de eventos que se combinan como una máscara de bits. Según la versión de Python, existen eventos para inicio y retorno de funciones Python, llamadas, saltos, instrucciones, excepciones y otros puntos.

events = sys.monitoring.events
mask = events.PY_START | events.PY_RETURN
sys.monitoring.set_events(TOOL_ID, mask)

Activa el conjunto mínimo. Monitorear cada instrucción cuando solo necesitas límites de función genera trabajo y datos innecesarios.

Registrar callbacks

Los callbacks se registran por evento. Sus argumentos dependen del evento, por lo que debes revisar la documentación de la versión soportada.

def on_start(code, instruction_offset):
    print("inicio:", code.co_name, instruction_offset)

sys.monitoring.register_callback(
    TOOL_ID,
    sys.monitoring.events.PY_START,
    on_start,
)

Mantén el callback corto. Es mejor incrementar contadores, escribir registros compactos en una cola o actualizar estructuras simples. Formatear logs, llamar servicios externos o ejecutar análisis complejo dentro del callback distorsiona el programa observado.

Monitoreo global y local

Los eventos globales afectan una superficie amplia. Los eventos locales permiten seleccionar objetos de código específicos. Esta capacidad es clave para reducir overhead.

Un profiler interno puede observar únicamente módulos de la aplicación e ignorar frameworks. Una herramienta de pruebas puede limitarse a funciones críticas. Un depurador puede activar detalle solo alrededor de una zona sospechosa.

Contador de llamadas

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,
)

# Ejecuta aquí la carga de trabajo.

sys.monitoring.set_events(TOOL_ID, 0)
sys.monitoring.free_tool_id(TOOL_ID)
print(calls)

En producción, usa try/finally, evita imprimir directamente y protege estructuras compartidas cuando existen hilos.

Buenas prácticas de rendimiento

Primero, selecciona pocos eventos. Segundo, filtra módulos y objetos de código. Tercero, mantén callbacks de tiempo constante cuando sea posible. Cuarto, agrega datos antes de exportarlos. Quinto, ofrece una opción para desactivar totalmente el monitoreo.

Mide la propia herramienta. Ejecuta benchmarks representativos con instrumentación activada y desactivada. Observa CPU, latencia, memoria y volumen de eventos. Si el monitor cambia demasiado el comportamiento, los resultados pueden ser engañosos.

Evitar reentrada

Un callback puede ejecutar código Python que también genera eventos. Sin protección, puede producir recursión. Usa una bandera thread-local o basada en contexto para impedir reentrada accidental. Mantén pocas dependencias y evita llamar funciones instrumentadas desde el callback.

El callback tampoco debería propagar excepciones hacia la aplicación. Captura errores internos, registra un diagnóstico compacto y desactiva la herramienta si su estado deja de ser confiable.

Hilos y asyncio

Los contadores compartidos necesitan sincronización o agregación segura. En servicios asíncronos, asocia observaciones con el contexto de la solicitud. El artículo sobre contextvars en Python explica cómo propagar contexto entre tareas. La guía de asyncio.Runner en Python aporta contexto sobre el ciclo de vida asíncrono.

Una arquitectura útil envía registros a una cola limitada y los procesa en otro worker. La cola acotada evita crecimiento infinito. Cuando se llena, decide si descartas muestras, agregas localmente o desactivas el detalle.

Logs, métricas y trazas

No escribas una línea de log por cada evento en un servicio ocupado. Agrega llamadas, duraciones, excepciones o muestras. Un registro estructurado puede incluir módulo, función, archivo, línea, tipo de evento e identificador de correlación.

Para métricas, contadores e histogramas suelen ser mejores que streams crudos. Para trazas, crea spans solo en límites relevantes. Filtra rutas, mensajes de excepción y datos sensibles antes de exportar.

Pruebas

Prueba funciones normales, métodos, generators, coroutines, llamadas anidadas, excepciones, recursión y cancelación. Confirma que los callbacks reciben los eventos previstos, que los filtros locales funcionan y que el cierre elimina registros.

Incluye pruebas de reentrada, concurrencia, desbordamiento de cola e inicialización parcial. Ejecuta una segunda prueba después del cierre para demostrar que no quedó ningún callback activo.

Compatibilidad

sys.monitoring no está disponible en versiones antiguas. Una biblioteca reutilizable debe detectarlo con hasattr(sys, "monitoring"). El fallback puede usar otro mecanismo, ofrecer menos funciones o mostrar un error claro.

Consulta la documentación oficial de sys.monitoring y la PEP 669. Para introspección complementaria, revisa inspect.signature en Python y inspect.getmembers_static en Python.

Arquitectura recomendada

Separa configuración, recolección, almacenamiento y exportación. La configuración elige eventos y filtros. Los callbacks generan registros mínimos. El almacenamiento agrega datos. La exportación convierte resultados en logs, métricas, archivos o interfaz.

Esta separación facilita benchmarks, pruebas y reemplazo de destinos. También permite modos distintos: contadores ligeros siempre activos y diagnóstico detallado habilitado temporalmente.

Seguridad y privacidad

La instrumentación puede revelar rutas, nombres de funciones, excepciones y estructura interna. Trata los datos como información operacional sensible. Aplica allowlists, redacta secretos, limita retención y restringe acceso.

No uses callbacks como lógica de negocio. La corrección de la aplicación nunca debe depender de que el monitor esté activo. Un fallo de observabilidad debe degradar el diagnóstico, no el servicio.

Cuándo elegir otra opción

Usa logging normal cuando eventos explícitos sean suficientes. Usa métricas para señales agregadas estables. Usa profilers por muestreo cuando basten estadísticas. Elige sys.monitoring cuando necesites eventos de ejecución y control selectivo.

Conclusión

sys.monitoring es una base potente para herramientas modernas de Python. Sus eventos selectivos, aislamiento por herramienta y monitoreo local reducen el costo. Con callbacks mínimos, filtros, limpieza, benchmarks, privacidad y pruebas robustas, puedes crear profilers, depuradores, cobertura y diagnósticos sin volver inestable la aplicación observada.

Compartilhe:

Facebook
WhatsApp
Twitter
LinkedIn

Contenido del artículo

    Artículos relacionados

    Desarrollador organizando datos con operator.attrgetter en Python
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    operator.attrgetter: ordena objetos por atributos

    Aprende operator.attrgetter en Python para ordenar, agrupar y transformar objetos por atributos simples o anidados con código claro.

    Ler mais

    Tempo de leitura: 4 minutos
    02/09/2026
    Programación asíncrona con asyncio.Runner en Python
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    asyncio.Runner: reutiliza el event loop con seguridad

    Aprende asyncio.Runner en Python para reutilizar el event loop, controlar contexto, señales, debug, cancelación y cierre asíncrono seguro.

    Ler mais

    Tempo de leitura: 7 minutos
    02/09/2026
    Compresión de datos binarios con Zstandard en Python
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    compression.zstd: Zstandard con streams y diccionarios

    Aprende compression.zstd en Python para comprimir datos con Zstandard, streaming, diccionarios y límites seguros.

    Ler mais

    Tempo de leitura: 7 minutos
    01/09/2026
    Aplicación Python empaquetada como archivo ejecutable con zipapp
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    zipapp en Python: crea apps ejecutables

    Aprende zipapp en Python para empaquetar aplicaciones como archivos pyz ejecutables, incluir dependencias y distribuirlas con seguridad.

    Ler mais

    Tempo de leitura: 5 minutos
    01/09/2026
    Código Python usado para componer funciones con functools.Placeholder
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    functools.Placeholder: huecos posicionales en partial

    Aprende functools.Placeholder en Python para dejar huecos posicionales en partial y crear APIs funcionales claras y reutilizables.

    Ler mais

    Tempo de leitura: 5 minutos
    31/08/2026
    Persona programando y analizando datos con Python
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    itertools.pairwise: compara elementos vecinos

    Aprende itertools.pairwise en Python para comparar elementos vecinos, detectar cambios, calcular diferencias y crear pipelines lazy claros.

    Ler mais

    Tempo de leitura: 4 minutos
    31/08/2026