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

    Código Python en un portátil para crear dataclasses dinámicas
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    make_dataclass decorator: transforma dataclasses

    Aprende a usar el parámetro decorator de make_dataclass para validar, registrar y transformar dataclasses dinámicas en Python.

    Ler mais

    Tempo de leitura: 6 minutos
    23/10/2026
    Estructura de código y XML para canonicalización con Python
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    ElementTree canonicalize: normaliza XML en Python

    Aprende ElementTree canonicalize en Python para comparar XML, generar hashes estables y controlar namespaces, espacios y comentarios.

    Ler mais

    Tempo de leitura: 5 minutos
    22/10/2026
    Código Python en una pantalla
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    T-strings y templatelib: interpolación estructurada

    Aprende t-strings y string.templatelib en Python para interpolación estructurada, renderizado seguro, logs y procesamiento personalizado.

    Ler mais

    Tempo de leitura: 6 minutos
    22/10/2026
    Base SQLite y código Python para exportación selectiva con iterdump
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    SQLite iterdump: crea dumps selectivos en Python

    Aprende sqlite3.Connection.iterdump con filtro para crear dumps SQLite selectivos, validar dependencias y restaurar con seguridad.

    Ler mais

    Tempo de leitura: 4 minutos
    21/10/2026
    Código y archivos que representan compresión de datos con Python
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    compression.zstd: Zstandard rápido en Python

    Aprende compression.zstd en Python para comprimir archivos y datos con velocidad, streaming, integridad y seguridad.

    Ler mais

    Tempo de leitura: 7 minutos
    21/10/2026
    Archivo de configuración y estructura de código para ConfigParser en Python
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    ConfigParser: lee INI sin sección en Python

    Aprende ConfigParser sin sección en Python con validación, tipos, compatibilidad, capas de configuración y escritura segura.

    Ler mais

    Tempo de leitura: 5 minutos
    20/10/2026