|
| 1 | +:mod:`sys.monitoring` --- Execution event monitoring |
| 2 | +==================================================== |
| 3 | + |
| 4 | +.. module:: sys.monitoring |
| 5 | + :synopsis: Access and control event monitoring |
| 6 | + |
| 7 | +----------------- |
| 8 | + |
| 9 | +.. note:: |
| 10 | + |
| 11 | + ``sys.monitoring`` is a namespace within the ``sys`` module, |
| 12 | + not an independent module, so there is no need to |
| 13 | + ``import sys.monitoring``, simply ``import sys`` and then use |
| 14 | + ``sys.monitoring``. |
| 15 | + |
| 16 | + |
| 17 | +This namespace provides access to the functions and constants necessary to |
| 18 | +activate and control event monitoring. |
| 19 | + |
| 20 | +As programs execute, events occur that might be of interest to tools that |
| 21 | +monitor execution. The :mod:`!sys.monitoring` namespace provides means to |
| 22 | +receive callbacks when events of interest occur. |
| 23 | + |
| 24 | +The monitoring API consists of three components: |
| 25 | + |
| 26 | +* Tool identifiers |
| 27 | +* Events |
| 28 | +* Callbacks |
| 29 | + |
| 30 | +Tool identifiers |
| 31 | +---------------- |
| 32 | + |
| 33 | +A tool identifier is an integer and associated name. |
| 34 | +Tool identifiers are used to discourage tools from interfering with each |
| 35 | +other and to allow multiple tools to operate at the same time. |
| 36 | +Currently tools are completely independent and cannot be used to |
| 37 | +monitor each other. This restriction may be lifted in the future. |
| 38 | + |
| 39 | +Before registering or activating events, a tool should choose an identifier. |
| 40 | +Identifiers are integers in the range 0 to 5. |
| 41 | + |
| 42 | +Registering and using tools |
| 43 | +''''''''''''''''''''''''''' |
| 44 | + |
| 45 | +.. function:: use_tool_id(id: int, name: str) -> None |
| 46 | + |
| 47 | + Must be called before ``id`` can be used. |
| 48 | + ``id`` must be in the range 0 to 5 inclusive. |
| 49 | + Raises a ``ValueError`` if ``id`` is in use. |
| 50 | + |
| 51 | +.. function:: free_tool_id(id: int) -> None |
| 52 | + |
| 53 | + Should be called once a tool no longer requires ``id``. |
| 54 | + |
| 55 | +.. function:: get_tool(id: int) -> str | None |
| 56 | + |
| 57 | + Returns the name of the tool if ``id`` is in use, |
| 58 | + otherwise it returns ``None``. |
| 59 | + ``id`` must be in the range 0 to 5 inclusive. |
| 60 | + |
| 61 | +All IDs are treated the same by the VM with regard to events, but the |
| 62 | +following IDs are pre-defined to make co-operation of tools easier:: |
| 63 | + |
| 64 | + sys.monitoring.DEBUGGER_ID = 0 |
| 65 | + sys.monitoring.COVERAGE_ID = 1 |
| 66 | + sys.monitoring.PROFILER_ID = 2 |
| 67 | + sys.monitoring.OPTIMIZER_ID = 5 |
| 68 | + |
| 69 | +There is no obligation to set an ID, nor is there anything preventing a tool |
| 70 | +from using an ID even it is already in use. |
| 71 | +However, tools are encouraged to use a unique ID and respect other tools. |
| 72 | + |
| 73 | +Events |
| 74 | +------ |
| 75 | + |
| 76 | +The following events are supported: |
| 77 | + |
| 78 | +BRANCH |
| 79 | + A conditional branch is taken (or not). |
| 80 | +CALL |
| 81 | + A call in Python code (event occurs before the call). |
| 82 | +C_RAISE |
| 83 | + Exception raised from any callable, except Python functions (event occurs after the exit). |
| 84 | +C_RETURN |
| 85 | + Return from any callable, except Python functions (event occurs after the return). |
| 86 | +EXCEPTION_HANDLED |
| 87 | + An exception is handled. |
| 88 | +INSTRUCTION |
| 89 | + A VM instruction is about to be executed. |
| 90 | +JUMP |
| 91 | + An unconditional jump in the control flow graph is made. |
| 92 | +LINE |
| 93 | + An instruction is about to be executed that has a different line number from the preceding instruction. |
| 94 | +PY_RESUME |
| 95 | + Resumption of a Python function (for generator and coroutine functions), except for throw() calls. |
| 96 | +PY_RETURN |
| 97 | + Return from a Python function (occurs immediately before the return, the callee's frame will be on the stack). |
| 98 | +PY_START |
| 99 | + Start of a Python function (occurs immediately after the call, the callee's frame will be on the stack) |
| 100 | +PY_THROW |
| 101 | + A Python function is resumed by a throw() call. |
| 102 | +PY_UNWIND |
| 103 | + Exit from a Python function during exception unwinding. |
| 104 | +PY_YIELD |
| 105 | + Yield from a Python function (occurs immediately before the yield, the callee's frame will be on the stack). |
| 106 | +RAISE |
| 107 | + An exception is raised, except those that cause a ``STOP_ITERATION`` event. |
| 108 | +RERAISE |
| 109 | + An exception is re-raised, for example at the end of a ``finally`` block. |
| 110 | +STOP_ITERATION |
| 111 | + An artificial ``StopIteration`` is raised; see `the STOP_ITERATION event`_. |
| 112 | + |
| 113 | +More events may be added in the future. |
| 114 | + |
| 115 | +These events are attributes of the :mod:`!sys.monitoring.events` namespace. |
| 116 | +Each event is represented as a power-of-2 integer constant. |
| 117 | +To define a set of events, simply bitwise or the individual events together. |
| 118 | +For example, to specify both ``PY_RETURN`` and ``PY_START`` events, use the |
| 119 | +expression ``PY_RETURN | PY_START``. |
| 120 | + |
| 121 | +Events are divided into three groups: |
| 122 | + |
| 123 | +Local events |
| 124 | +'''''''''''' |
| 125 | + |
| 126 | +Local events are associated with normal execution of the program and happen |
| 127 | +at clearly defined locations. All local events can be disabled. |
| 128 | +The local events are: |
| 129 | + |
| 130 | +* PY_START |
| 131 | +* PY_RESUME |
| 132 | +* PY_RETURN |
| 133 | +* PY_YIELD |
| 134 | +* CALL |
| 135 | +* LINE |
| 136 | +* INSTRUCTION |
| 137 | +* JUMP |
| 138 | +* BRANCH |
| 139 | +* STOP_ITERATION |
| 140 | + |
| 141 | +Ancillary events |
| 142 | +'''''''''''''''' |
| 143 | + |
| 144 | +Ancillary events can be monitored like other events, but are controlled |
| 145 | +by another event: |
| 146 | + |
| 147 | +* C_RAISE |
| 148 | +* C_RETURN |
| 149 | + |
| 150 | +The ``C_RETURN`` and ``C_RAISE`` events are are controlled by the ``CALL`` |
| 151 | +event. ``C_RETURN`` and ``C_RAISE`` events will only be seen if the |
| 152 | +corresponding ``CALL`` event is being monitored. |
| 153 | + |
| 154 | +Other events |
| 155 | +'''''''''''' |
| 156 | + |
| 157 | +Other events are not necessarily tied to a specific location in the |
| 158 | +program and cannot be individually disabled. |
| 159 | + |
| 160 | +The other events that can be monitored are: |
| 161 | + |
| 162 | +* PY_THROW |
| 163 | +* PY_UNWIND |
| 164 | +* RAISE |
| 165 | +* EXCEPTION_HANDLED |
| 166 | + |
| 167 | + |
| 168 | +The STOP_ITERATION event |
| 169 | +'''''''''''''''''''''''' |
| 170 | + |
| 171 | +:pep:`PEP 380 <380#use-of-stopiteration-to-return-values>` |
| 172 | +specifies that a ``StopIteration`` exception is raised when returning a value |
| 173 | +from a generator or coroutine. However, this is a very inefficient way to |
| 174 | +return a value, so some Python implementations, notably CPython 3.12+, do not |
| 175 | +raise an exception unless it would be visible to other code. |
| 176 | + |
| 177 | +To allow tools to monitor for real exceptions without slowing down generators |
| 178 | +and coroutines, the ``STOP_ITERATION`` event is provided. |
| 179 | +``STOP_ITERATION`` can be locally disabled, unlike ``RAISE``. |
| 180 | + |
| 181 | + |
| 182 | +Turning events on and off |
| 183 | +------------------------- |
| 184 | + |
| 185 | +In order to monitor an event, it must be turned on and a callback registered. |
| 186 | +Events can be turned on or off by setting the events either globally or |
| 187 | +for a particular code object. |
| 188 | + |
| 189 | + |
| 190 | +Setting events globally |
| 191 | +''''''''''''''''''''''' |
| 192 | + |
| 193 | +Events can be controlled globally by modifying the set of events being monitored. |
| 194 | + |
| 195 | +.. function:: get_events(tool_id: int) -> int |
| 196 | + |
| 197 | + Returns the ``int`` representing all the active events. |
| 198 | + |
| 199 | +.. function:: set_events(tool_id: int, event_set: int) |
| 200 | + |
| 201 | + Activates all events which are set in ``event_set``. |
| 202 | + Raises a ``ValueError`` if ``tool_id`` is not in use. |
| 203 | + |
| 204 | +No events are active by default. |
| 205 | + |
| 206 | +Per code object events |
| 207 | +'''''''''''''''''''''' |
| 208 | + |
| 209 | +Events can also be controlled on a per code object basis. |
| 210 | + |
| 211 | +.. function:: get_local_events(tool_id: int, code: CodeType) -> int |
| 212 | + |
| 213 | + Returns all the local events for ``code`` |
| 214 | + |
| 215 | +.. function:: set_local_events(tool_id: int, code: CodeType, event_set: int) |
| 216 | + |
| 217 | + Activates all the local events for ``code`` which are set in ``event_set``. |
| 218 | + Raises a ``ValueError`` if ``tool_id`` is not in use. |
| 219 | + |
| 220 | +Local events add to global events, but do not mask them. |
| 221 | +In other words, all global events will trigger for a code object, |
| 222 | +regardless of the local events. |
| 223 | + |
| 224 | + |
| 225 | +Disabling events |
| 226 | +'''''''''''''''' |
| 227 | + |
| 228 | +Local events can be disabled for a specific code location by returning |
| 229 | +``sys.monitoring.DISABLE`` from a callback function. This does not change |
| 230 | +which events are set, or any other code locations for the same event. |
| 231 | + |
| 232 | +Disabling events for specific locations is very important for high |
| 233 | +performance monitoring. For example, a program can be run under a |
| 234 | +debugger with no overhead if the debugger disables all monitoring |
| 235 | +except for a few breakpoints. |
| 236 | + |
| 237 | + |
| 238 | +Registering callback functions |
| 239 | +------------------------------ |
| 240 | + |
| 241 | +To register a callable for events call |
| 242 | + |
| 243 | +.. function:: register_callback(tool_id: int, event: int, func: Callable | None) -> Callable | None |
| 244 | + |
| 245 | + Registers the callable ``func`` for the ``event`` with the given ``tool_id`` |
| 246 | + |
| 247 | + If another callback was registered for the given ``tool_id`` and ``event``, |
| 248 | + it is unregistered and returned. |
| 249 | + Otherwise ``register_callback`` returns ``None``. |
| 250 | + |
| 251 | + |
| 252 | +Functions can be unregistered by calling |
| 253 | +``sys.monitoring.register_callback(tool_id, event, None)``. |
| 254 | + |
| 255 | +Callback functions can be registered and unregistered at any time. |
| 256 | + |
| 257 | +Registering or unregistering a callback function will generate a ``sys.audit`` event. |
| 258 | + |
| 259 | + |
| 260 | +Callback function arguments |
| 261 | +''''''''''''''''''''''''''' |
| 262 | + |
| 263 | +When an active event occurs, the registered callback function is called. |
| 264 | +Different events will provide the callback function with different arguments, as follows: |
| 265 | + |
| 266 | +* ``PY_START`` and ``PY_RESUME``:: |
| 267 | + |
| 268 | + func(code: CodeType, instruction_offset: int) -> DISABLE | Any |
| 269 | + |
| 270 | +* ``PY_RETURN`` and ``PY_YIELD``: |
| 271 | + |
| 272 | + ``func(code: CodeType, instruction_offset: int, retval: object) -> DISABLE | Any`` |
| 273 | + |
| 274 | +* ``CALL``, ``C_RAISE`` and ``C_RETURN``: |
| 275 | + |
| 276 | + ``func(code: CodeType, instruction_offset: int, callable: object, arg0: object | MISSING) -> DISABLE | Any`` |
| 277 | + |
| 278 | + If there are no arguments, ``arg0`` is set to ``MISSING``. |
| 279 | + |
| 280 | +* ``RAISE``, ``RERAISE``, ``EXCEPTION_HANDLED``, ``PY_UNWIND``, ``PY_THROW`` and ``STOP_ITERATION``: |
| 281 | + |
| 282 | + ``func(code: CodeType, instruction_offset: int, exception: BaseException) -> DISABLE | Any`` |
| 283 | + |
| 284 | +* ``LINE``: |
| 285 | + |
| 286 | + ``func(code: CodeType, line_number: int) -> DISABLE | Any`` |
| 287 | + |
| 288 | +* ``BRANCH`` and ``JUMP``: |
| 289 | + |
| 290 | + ``func(code: CodeType, instruction_offset: int, destination_offset: int) -> DISABLE | Any`` |
| 291 | + |
| 292 | + Note that the ``destination_offset`` is where the code will next execute. |
| 293 | + For an untaken branch this will be the offset of the instruction following |
| 294 | + the branch. |
| 295 | + |
| 296 | +* ``INSTRUCTION``: |
| 297 | + |
| 298 | + ``func(code: CodeType, instruction_offset: int) -> DISABLE | Any`` |
| 299 | + |
| 300 | + |
0 commit comments