Nota

¡Ayúdanos a traducir la documentación oficial de Python al Español! Puedes encontrar más información en Como contribuir. Ayuda a acercar Python a más personas de habla hispana.

sys.monitoring — Monitoreo de eventos de ejecución


Nota

sys.monitoring es un espacio de nombres dentro del módulo sys, no un módulo independiente, así que no hay necesidad de usar import sys.monitoring, simplemente use import sys y luego sys.monitoring.

Este espacio de nombres proporciona acceso a las funciones y constantes necesarias para activar y controlar el monitoreo de eventos.

A medida que se ejecutan los programas, ocurren eventos que podrían ser de interés para las herramientas que monitorean la ejecución. El espacio de nombres sys.monitoring proporciona medios para recibir retrollamadas cuando ocurren eventos de interés.

La API de monitoreo consta de tres componentes:

  • Identificadores de herramientas

  • Eventos

  • Retrollamadas

Identificadores de herramientas

Un identificador de herramienta es un número entero y un nombre asociado. Los identificadores de herramientas se utilizan para evitar que las herramientas interfieran entre sí y para permitir que varias herramientas funcionen al mismo tiempo. Actualmente las herramientas son completamente independientes y no se pueden utilizar para monitorearse entre sí. Esta restricción podría eliminarse en el futuro.

Antes de registrar o activar eventos, una herramienta debe elegir un identificador. Los identificadores son números enteros en el rango de 0 a 5.

Registro y uso de herramientas

sys.monitoring.use_tool_id(id: int, name: str) None

Debe llamarse antes de poder utilizar id. id debe estar inclusive en el rango de 0 a 5. Lanza un ValueError si id está en uso.

sys.monitoring.free_tool_id(id: int) None

Se debe llamar una vez que una herramienta ya no requiera id.

sys.monitoring.get_tool(id: int) str | None

Retorna el nombre de la herramienta si id está en uso; de lo contrario, devuelve None. id debe estar dentro del rango de 0 a 5.

La máquina virtual trata todos los ID de la misma manera con respecto a los eventos, pero los siguientes ID están predefinidos para facilitar la cooperación de las herramientas:

sys.monitoring.DEBUGGER_ID = 0
sys.monitoring.COVERAGE_ID = 1
sys.monitoring.PROFILER_ID = 2
sys.monitoring.OPTIMIZER_ID = 5

No hay obligación de establecer un ID, ni hay nada que impida que una herramienta use un ID, incluso si ya está en uso. Sin embargo, se recomienda que las herramientas utilicen un identificación única y respeten otras herramientas.

Eventos

Son aceptados los siguientes eventos:

BRANCH

Una rama condicional es aceptada (o no).

CALL

Una llamada en código Python (el evento ocurre antes de la llamada).

C_RAISE

Excepción generada por cualquier función invocable, excepto las funciones Python (el evento ocurre después de la salida).

C_RETURN

Retorno de cualquier función invocable, excepto las funciones Python (el evento ocurre después del retorno).

EXCEPTION_HANDLED

Se maneja una excepción.

INSTRUCTION

Está a punto de ejecutarse una instrucción de VM.

JUMP

Se realiza un salto incondicional en el gráfico de flujo de control.

LINE

Está a punto de ejecutarse una instrucción que tiene un número de línea diferente al de la instrucción anterior.

PY_RESUME

Reanudación de una función Python (para funciones generadoras y de corutina), excepto para llamadas throw().

PY_RETURN

Retorna de una función Python (ocurre inmediatamente antes del retorno, el marco del destinatario estará en la pila).

PY_START

Inicio de una función Python (ocurre inmediatamente después de la llamada, el marco del destinatario estará en la pila)

PY_THROW

Una función Python se reanuda mediante una llamada throw().

PY_UNWIND

Salida de una función Python durante la resolución de excepciones.

PY_YIELD

Rinde (yield) desde una función Python (ocurre inmediatamente antes del rendimiento, el marco del destinatario estará en la pila).

RAISE

Se lanza una excepción, excepto aquellas que causan un evento STOP_ITERATION.

RERAISE

Se vuelve a lanzar una excepción, por ejemplo, al final de un bloque finally.

STOP_ITERATION

Se genera un StopIteration artificial; ver el evento STOP_ITERATION.

Es posible que se agreguen más eventos en el futuro.

Estos eventos son atributos del espacio de nombres sys.monitoring.events. Cada evento se representa como una constante entera de potencia de 2. Para definir un conjunto de eventos, simplemente combine los eventos individuales bit a bit con OR. Por ejemplo, para especificar eventos PY_RETURN y PY_START, use la expresión PY_RETURN | PY_START.

Los eventos se dividen en tres grupos:

Eventos locales

Los eventos locales están asociados con la ejecución normal del programa y ocurren en lugares claramente definidos. Todos los eventos locales se pueden desactivar. Los eventos locales son:

  • PY_START

  • PY_RESUME

  • PY_RETURN

  • PY_YIELD

  • CALL

  • LINE

  • INSTRUCTION

  • JUMP

  • BRANCH

  • STOP_ITERATION

Eventos auxiliares

Los eventos auxiliares se pueden monitorear como otros eventos, pero están controlados por otros eventos:

  • C_RAISE

  • C_RETURN

El C_RETURN y C_RAISE son eventos controlados por el evento CALL. Los eventos C_RETURN y C_RAISE serán vistos si el evento correspondiente CALL está siendo monitoreado.

Otros eventos

Otros eventos no están necesariamente vinculados a una ubicación específica del programa y no se pueden desactivar individualmente.

Los otros eventos que se pueden monitorear son:

  • PY_THROW

  • PY_UNWIND

  • RAISE

  • EXCEPTION_HANDLED

El evento STOP_ITERATION

PEP 380 especifica que se lanza una excepción StopIteration al retornar un valor de un generador o corutina. Sin embargo, esta es una forma muy ineficiente de devolver un valor, por lo que algunas implementaciones de Python, en particular CPython 3.12+, no lanzan una excepción a menos que sea visible para otro código.

Para permitir que las herramientas monitoreen excepciones reales sin ralentizar los generadores y las corrutinas, se proporciona el evento STOP_ITERATION. STOP_ITERATION se puede desactivar localmente, a diferencia de RAISE.

Activar y desactivar eventos

Para monitorear un evento, se debe activar y registrar una retrollamada. Los eventos se pueden activar o desactivar configurándolos globalmente o para un objeto de código en particular.

Configuración de eventos globalmente

Los eventos se pueden controlar globalmente modificando el conjunto de eventos que están siendo monitoreados.

sys.monitoring.get_events(tool_id: int) int

Retorna el int que representa todos los eventos activos.

sys.monitoring.set_events(tool_id: int, event_set: int)

Activa todos los eventos que están configurados en event_set. Lanza un ValueError si tool_id no está en uso.

No hay eventos activos de forma predeterminada.

Eventos por objeto de código

Los eventos también se pueden controlar por objeto de código.

sys.monitoring.get_local_events(tool_id: int, code: CodeType) int

Retorna todos los eventos locales de code

sys.monitoring.set_local_events(tool_id: int, code: CodeType, event_set: int)

Activa todos los eventos locales para code que están configurados en event_set. Lanza un ValueError si tool_id no está en uso.

Los eventos locales se suman a los eventos globales, pero no los enmascaran. En otras palabras, todos los eventos globales se activarán para un objeto de código, independientemente de los eventos locales.

Deshabilitando eventos

Los eventos locales se pueden deshabilitar para una ubicación de código específica retornando sys.monitoring.DISABLE desde una función de retrollamada. Esto no cambia cuales eventos se configuran ni ninguna otra ubicación de código para el mismo evento.

Deshabilitar eventos para ubicaciones específicas es muy importante para el monitoreo de alto rendimiento. Por ejemplo, un programa se puede ejecutar con un depurador sin gastos adicionales si el depurador desactiva toda la supervisión excepto algunos puntos de interrupción.

Registrando funciones de retrollamada

Para registrar un invocable para eventos llame

sys.monitoring.register_callback(tool_id: int, event: int, func: Callable | None) Callable | None

Registra el invocable func para el event con el tool_id proporcionado

Si se registró otra retrollamada por los tool_id y event proporcionados, ésta se cancela y se retorna. De lo contrario register_callback retorna None.

Funciones pueden ser canceladas llamando sys.monitoring.register_callback(tool_id, event, None).

Las funciones de retrollamada se pueden registrar y cancelar en cualquier momento.

Registrar o cancelar el registro de una función de retrollamada generará un evento sys.audit.

Argumentos de la función de retrollamada

Cuando ocurre un evento activo, se llama a la función de retrollamada registrada. Diferentes eventos proporcionarán a la función de retrollamada con diferentes argumentos, de la siguiente manera:

  • PY_START y PY_RESUME:

    func(code: CodeType, instruction_offset: int) -> DISABLE | Any
    
  • PY_RETURN y PY_YIELD:

    func(code: CodeType, instruction_offset: int, retval: object) -> DISABLE | Any

  • CALL, C_RAISE y C_RETURN:

    func(code: CodeType, instruction_offset: int, callable: object, arg0: object | MISSING) -> DISABLE | Any

    Si no hay argumentos, arg0 se establece como MISSING.

  • RAISE, RERAISE, EXCEPTION_HANDLED, PY_UNWIND, PY_THROW y STOP_ITERATION:

    func(code: CodeType, instruction_offset: int, exception: BaseException) -> DISABLE | Any

  • LINE:

    func(code: CodeType, line_number: int) -> DISABLE | Any

  • BRANCH y JUMP:

    func(code: CodeType, instruction_offset: int, destination_offset: int) -> DISABLE | Any

    Tenga en cuenta que destination_offset es donde el siguiente código se ejecutará. Para una rama no tomada, este será el desplazamiento de la instrucción que sigue la rama.

  • INSTRUCTION:

    func(code: CodeType, instruction_offset: int) -> DISABLE | Any