sys.monitoring — Мониторинг событий выполнения

Added in version 3.12.


Примечание

sys.monitoring - это пространство имен внутри модуля sys, а не самостоятельный модуль, поэтому нет необходимости в import sys.monitoring, достаточно import sys, а затем использовать sys.monitoring.

Это пространство имен предоставляет доступ к функциям и константам, необходимым для активации и управления мониторингом событий.

В процессе выполнения программ происходят события, которые могут представлять интерес для инструментов, следящих за выполнением. Пространство имен sys.monitoring предоставляет средства для получения обратных вызовов при наступлении интересующих событий.

API мониторинга состоит из трех компонентов:

Идентификаторы инструментов

Идентификатор инструмента - это целое число и связанное с ним имя. Идентификаторы инструментов используются для того, чтобы предотвратить вмешательство инструментов друг в друга и позволить нескольким инструментам работать одновременно. В настоящее время инструменты полностью независимы и не могут использоваться для мониторинга друг друга. В будущем это ограничение может быть снято.

Прежде чем регистрировать или активировать события, инструмент должен выбрать идентификатор. Идентификаторы - это целые числа в диапазоне от 0 до 5 включительно.

Регистрация и использование инструментов

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

Должен быть вызван перед использованием tool_id. tool_id должен быть в диапазоне от 0 до 5 включительно. Вызывает сообщение ValueError, если tool_id используется.

sys.monitoring.free_tool_id(tool_id: int, /) None

Вызывается, когда инструмент больше не требует tool_id.

Примечание

free_tool_id() не отключит глобальные или локальные события, связанные с tool_id, и не снимет с регистрации какие-либо функции обратного вызова. Эта функция предназначена только для уведомления виртуальной машины о том, что конкретный tool_id больше не используется.

sys.monitoring.get_tool(tool_id: int, /) str | None

Возвращает имя инструмента, если tool_id используется, в противном случае возвращает None. tool_id должен находиться в диапазоне от 0 до 5 включительно.

Все идентификаторы обрабатываются VM одинаково в отношении событий, но для облегчения совместной работы инструментов предварительно определены следующие идентификаторы:

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

События

Поддерживаются следующие события:

sys.monitoring.events.BRANCH

Выполняется (или не выполняется) условная ветвь.

sys.monitoring.events.CALL

Вызов в коде Python (событие происходит до вызова).

sys.monitoring.events.C_RAISE

Исключение, вызванное из любого вызываемого объекта, за исключением функций Python (событие происходит после выхода).

sys.monitoring.events.C_RETURN

Возврат из любого вызываемого объекта, за исключением функций Python (событие происходит после возврата).

sys.monitoring.events.EXCEPTION_HANDLED

Исключение будет обработано.

sys.monitoring.events.INSTRUCTION

Сейчас будет выполнена инструкция VM.

sys.monitoring.events.JUMP

Осуществляется безусловный переход в графе потока управления.

sys.monitoring.events.LINE

Сейчас будет выполнена инструкция, номер строки которой отличается от номера строки предыдущей инструкции.

sys.monitoring.events.PY_RESUME

Возобновление функции Python (для генераторов и коретиновых функций), за исключением вызовов throw().

sys.monitoring.events.PY_RETURN

Возврат из функции Python (происходит непосредственно перед возвратом, фрейм вызывающего будет находиться в стеке).

sys.monitoring.events.PY_START

Начало функции Python (происходит сразу после вызова, фрейм вызывающего будет находиться в стеке)

sys.monitoring.events.PY_THROW

Функция Python возобновляется вызовом throw().

sys.monitoring.events.PY_UNWIND

Выход из функции Python во время разворачивания исключения.

sys.monitoring.events.PY_YIELD

Выход из функции Python (происходит непосредственно перед выходом, фрейм вызывающего будет находиться в стеке).

sys.monitoring.events.RAISE

Возникает исключение, за исключением тех, которые вызывают событие STOP_ITERATION.

sys.monitoring.events.RERAISE

Исключение поднимается повторно, например, в конце блока finally.

sys.monitoring.events.STOP_ITERATION

Поднимается искусственный StopIteration; см. the STOP_ITERATION event.

В будущем могут быть добавлены новые мероприятия.

Эти события являются атрибутами пространства имен sys.monitoring.events. Каждое событие представлено в виде целочисленной константы мощностью 2. Чтобы определить набор событий, просто выполните побитовую комбинацию отдельных событий. Например, чтобы указать оба события PY_RETURN и PY_START, используйте выражение PY_RETURN | PY_START.

sys.monitoring.events.NO_EVENTS

Псевдоним для 0, чтобы пользователи могли выполнять явные сравнения, например:

if get_events(DEBUGGER_ID) == NO_EVENTS:
    ...

События разделены на три группы:

Местные события

Локальные события связаны с нормальным выполнением программы и происходят в четко определенных местах. Все локальные события можно отключить. К локальным событиям относятся:

Вспомогательные мероприятия

Вспомогательные события можно отслеживать, как и другие события, но они контролируются другим событием:

События C_RETURN и C_RAISE контролируются событием CALL. События C_RETURN и C_RAISE будут видны, только если отслеживается соответствующее событие CALL.

Другие события

Другие события не обязательно привязаны к конкретному месту в программе и не могут быть индивидуально отключены.

Другими событиями, которые можно отслеживать, являются:

Событие STOP_ITERATION

PEP 380 указывает, что при возврате значения из генератора или корутины возбуждается исключение StopIteration. Однако это очень неэффективный способ возврата значения, поэтому некоторые реализации Python, в частности CPython 3.12+, не поднимают исключение, если это не будет заметно для другого кода.

Чтобы инструменты могли отслеживать реальные исключения без замедления работы генераторов и корутинов, предусмотрено событие STOP_ITERATION. STOP_ITERATION может быть локально отключен, в отличие от RAISE.

Включение и выключение событий

Для того чтобы отслеживать событие, его необходимо включить и зарегистрировать соответствующий обратный вызов. События можно включить или выключить, задав их либо глобально, либо для конкретного объекта кода.

Глобальная настройка событий

Событиями можно управлять глобально, изменяя набор отслеживаемых событий.

sys.monitoring.get_events(tool_id: int, /) int

Возвращает int, представляющий все активные события.

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

Активирует все события, заданные в event_set. Вызывает ошибку ValueError, если tool_id не используется.

По умолчанию ни одно событие не активно.

События для каждого объекта кода

События также можно контролировать на основе каждого объекта кода. Определенные ниже функции, принимающие значение types.CodeType, должны быть готовы принять объект, похожий на него, от функций, не определенных в Python (см. API Monitorong C).

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

Возвращает все локальные события для code.

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

Активирует все локальные события для code, заданные в event_set. Вызывает ошибку ValueError, если tool_id не используется.

Локальные события добавляются к глобальным, но не маскируют их. Другими словами, все глобальные события будут срабатывать для объекта кода, независимо от локальных событий.

Отключение событий

sys.monitoring.DISABLE

Специальное значение, которое может быть возвращено из функции обратного вызова для отключения событий для текущего местоположения кода.

Локальные события могут быть отключены для определенного места кода путем возврата sys.monitoring.DISABLE из функции обратного вызова. При этом не изменяется, какие события устанавливаются, и не изменяются другие кодовые места для того же события.

Отключение событий для определенных мест очень важно для высокопроизводительного мониторинга. Например, программа может быть запущена под отладчиком без каких-либо накладных расходов, если отладчик отключит весь мониторинг, кроме нескольких точек останова.

sys.monitoring.restart_events() None

Включите все события, которые были отключены с помощью sys.monitoring.DISABLE для всех инструментов.

Регистрация функций обратного вызова

Чтобы зарегистрировать вызываемый элемент для событий, вызовите

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

Регистрирует вызываемую функцию для события с заданным tool_id.

Если для данного tool_id и event был зарегистрирован другой обратный вызов, то он снимается с регистрации и возвращается. В противном случае register_callback() возвращается None.

Функции можно снять с регистрации, вызвав sys.monitoring.register_callback(tool_id, event, None).

Функции обратного вызова могут быть зарегистрированы и сняты с регистрации в любое время.

Регистрация или снятие с регистрации функции обратного вызова приведет к появлению события sys.audit().

Аргументы функции обратного вызова

sys.monitoring.MISSING

Специальное значение, которое передается функции обратного вызова, чтобы указать на отсутствие аргументов в вызове.

Когда происходит активное событие, вызывается зарегистрированная функция обратного вызова. Различные события предоставляют функции обратного вызова различные аргументы, как показано ниже:

  • PY_START и PY_RESUME:

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

    func(code: CodeType, instruction_offset: int, retval: object) -> DISABLE | Any
    
  • CALL, C_RAISE и C_RETURN:

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

    Если аргументов нет, arg0 устанавливается в sys.monitoring.MISSING.

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

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

    func(code: CodeType, line_number: int) -> DISABLE | Any
    
  • BRANCH и JUMP:

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

    Обратите внимание, что смещение_назначения - это место, где код будет выполняться в следующий раз. Для непринятого ответвления это будет смещение инструкции, следующей за ответвлением.

  • INSTRUCTION:

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