# `sys.monitoring` — Monitoramento de eventos de execução

Adicionado na versão 3.12.

Nota

`sys.monitoring` é um espaço de nomes dentro do módulo `sys`, não um módulo independente, então não há necessidade de importá-lo com `import sys.monitoring`, bastando usar `import sys` e então usar `sys.monitoring`.

Esse espaço de nomes fornece acesso às funções e constantes necessárias para ativar e controlar o monitoramento de eventos.

À medida que os programas são executados, ocorrem eventos que podem ser de interesse para as ferramentas que monitoram a execução. O espaço de nomes `sys.monitoring` fornece meios para receber retornos de chamada quando ocorrem eventos de interesse.

A API de monitoramento consiste em três componentes:

- Identificadores de ferramenta

- Eventos

- Funções de retorno de chamadas

## Identificadores de ferramenta

Um identificador de ferramenta é um número inteiro e o nome associado. Os identificadores de ferramenta são usados para evitar que as ferramentas interfiram umas nas outras e para permitir que várias ferramentas operem ao mesmo tempo. Atualmente, as ferramentas são totalmente independentes e não podem ser usadas para monitorar umas às outras. Essa restrição poderá ser suspensa no futuro.

Antes de registrar ou ativar eventos, uma ferramenta deve escolher um identificador. Os identificadores são números inteiros no intervalo de 0 a 5, inclusive.

### Registro e uso de ferramentas

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

  Deve ser chamado antes que tool_id possa ser usado. tool_id deve estar no intervalo de 0 a 5, inclusive. Levanta um `ValueError` se tool_id estiver em uso.

sys.monitoring.clear_tool_id(tool_id: int, /) → None

  Cancela o registro de todos os eventos e funções de retorno de chamada associados a tool_id.

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

  Deve ser chamado quando uma ferramenta não precisar mais de tool_id. Chamará `clear_tool_id()` antes de liberar tool_id.

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

  Retorna o nome da ferramenta se tool_id estiver em uso; caso contrário, retorna `None`. tool_id deve estar no intervalo de 0 a 5, inclusive.

Todas as IDs são tratadas da mesma forma pela VM com relação aos eventos, mas as seguintes IDs são predefinidas para facilitar a cooperação entre as ferramentas:

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

## Eventos

Os seguintes eventos são suportados:

sys.monitoring.events.BRANCH_LEFT

  Uma ramificação condicional vai para a esquerda.

  Cabe à ferramenta determinar como apresentar os ramos “esquerdo” e “direito”. Não há garantia de qual ramo é “esquerdo” e qual é “direito”, exceto que será consistente durante toda a duração do programa.

sys.monitoring.events.BRANCH_RIGHT

  Uma ramificação condicional vai para a direita.

sys.monitoring.events.CALL

  Uma chamada no código Python (o evento ocorre antes da chamada).

sys.monitoring.events.C_RAISE

  Uma exceção levantada por qualquer chamável, exceto funções Python (o evento ocorre após a saída).

sys.monitoring.events.C_RETURN

  Retorno de qualquer chamável, exceto por funções Python (o evento ocorre após o retorno).

sys.monitoring.events.EXCEPTION_HANDLED

  Uma exceção é tratada.

sys.monitoring.events.INSTRUCTION

  Uma instrução VM está prestes a ser executada.

sys.monitoring.events.JUMP

  É feito um salto incondicional no gráfico do fluxo de controle.

sys.monitoring.events.LINE

  Está prestes a ser executada uma instrução que tem um número de linha diferente da instrução anterior.

sys.monitoring.events.PY_RESUME

  Retomada de uma função Python (para funções geradoras e de corrotina), exceto para chamadas `throw()`.

sys.monitoring.events.PY_RETURN

  Retorno de uma função Python (ocorre imediatamente antes do retorno, o quadro do receptor estará na pilha).

sys.monitoring.events.PY_START

  Início de uma função Python (ocorre imediatamente após a chamada, o quadro do receptor da chamada estará na pilha)

sys.monitoring.events.PY_THROW

  Uma função Python é retomada por uma chamada `throw()`.

sys.monitoring.events.PY_UNWIND

  Saída de uma função Python durante o desenrolamento de uma exceção. Isso inclui exceções levantadas diretamente na função e que podem continuar a se propagar.

sys.monitoring.events.PY_YIELD

  Produz de uma função Python (ocorre imediatamente antes do yield, o quadro do receptor estará na pilha).

sys.monitoring.events.RAISE

  Uma exceção é levantada, exceto aquelas que causam um evento `STOP_ITERATION`.

sys.monitoring.events.RERAISE

  Uma exceção é levantada novamente, por exemplo, no final de um bloco `finally`.

sys.monitoring.events.STOP_ITERATION

  Uma exceção artificial `StopIteration` é levantada; consulte o evento STOP_ITERATION.

Mais eventos poderão ser adicionados no futuro.

Esses eventos são atributos do espaço de nomes `sys.monitoring.events`. Cada evento é representado como uma constante de potência de 2 inteiros. Para definir um conjunto de eventos, basta aplicar OU (OR) bit a bit nos eventos individuais juntos. Por exemplo, para especificar os eventos `PY_RETURN` e `PY_START`, use a expressão `PY_RETURN | PY_START`.

sys.monitoring.events.NO_EVENTS

  Um apelido para `0` para que os usuários possam fazer comparações explícitas como:

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

  Definir este evento desativa todos os eventos.

### Eventos locais

Os eventos locais estão associados à execução normal do programa e ocorrem em locais claramente definidos. Todos os eventos locais podem ser desativados. Os eventos locais são:

- `PY_START`

- `PY_RESUME`

- `PY_RETURN`

- `PY_YIELD`

- `CALL`

- `LINE`

- `INSTRUCTION`

- `JUMP`

- `BRANCH_LEFT`

- `BRANCH_RIGHT`

- `STOP_ITERATION`

### Evento descontinuado

- `BRANCH`

O evento `BRANCH` foi descontinuado na versão 3.14. Usar os eventos `BRANCH_LEFT` e `BRANCH_RIGHT` proporcionará um desempenho muito melhor, pois podem ser desabilitados independentemente.

### Eventos auxiliares

Os eventos auxiliares podem ser monitorados como outros eventos, mas são controlados por outro evento:

- `C_RAISE`

- `C_RETURN`

Os eventos `C_RETURN` e `C_RAISE` são controlados pelo evento `CALL`. Os eventos `C_RETURN` e `C_RAISE` só serão vistos se o evento `CALL` correspondente estiver sendo monitorado.

### Outros eventos

Outros eventos não estão necessariamente vinculados a um local específico no programa e não podem ser desativados individualmente.

Os outros eventos que podem ser monitorados são:

- `PY_THROW`

- `PY_UNWIND`

- `RAISE`

- `EXCEPTION_HANDLED`

### O evento STOP_ITERATION

PEP 380 especifica que uma exceção `StopIteration` é levantada ao retornar um valor de um gerador ou corrotina. No entanto, essa é uma maneira muito ineficiente de retornar um valor, portanto, algumas implementações do Python, especialmente o CPython 3.12+, não levantam uma exceção, a menos que ela seja visível para outro código.

Para permitir que as ferramentas monitorem exceções reais sem reduzir a velocidade dos geradores e das corrotinas, o evento `STOP_ITERATION` é fornecido. O `STOP_ITERATION` pode ser desativado localmente, ao contrário do `RAISE`.

Observe que o evento `STOP_ITERATION` e o evento `RAISE` para uma exceção `StopIteration` são equivalentes e tratados como intercambiáveis ao gerar eventos. As implementações favorecerão `STOP_ITERATION` por questões de desempenho, mas podem gerar um evento `RAISE` com uma `StopIteration`.

## Ativação e desativação de eventos

Para monitorar um evento, ele deve ser ativado e uma função de retorno correspondente deve ser registrada. Os eventos podem ser ativados ou desativados definindo-os globalmente e/ou para um objeto código específico. Um evento vai acionar apenas uma vez, mesmo se ele for ligado globalmente e localmente.

### Definir eventos globalmente

Os eventos podem ser controlados globalmente, modificando o conjunto de eventos que estão sendo monitorados.

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

  Retorna o endereço `int` que representa todos os eventos ativos.

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

  Ativa todos os eventos definidos em event_set. Levanta um `ValueError` se tool_id não estiver em uso.

Nenhum evento está ativo por padrão.

### Eventos por objeto código

Os eventos também podem ser controlados por objeto código. As funções definidas abaixo que aceitam um `types.CodeType` devem estar preparadas para aceitar um objeto semelhante de funções que não são definidas no Python (veja API C de monitoramento).

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

  Retorna todos os eventos locais para code

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

  Ativa todos os eventos locais para code que estão definidos em event_set. Levanta a `ValueError` se tool_id não estiver em uso.

### Desativação de eventos

sys.monitoring.DISABLE

  Um valor especial que pode ser retornado de um função de retorno função para desativar eventos para o local do código atual.

Os eventos locais podem ser desativados para um local de código específico, retornando `sys.monitoring.DISABLE` de uma função de retorno de chamada. Isso não altera quais eventos são definidos ou quaisquer outros locais de código para o mesmo evento.

A desativação de eventos para locais específicos é muito importante para o monitoramento de alto desempenho. Por exemplo, um programa pode ser executado em um depurador sem sobrecarga se o depurador desativar todo o monitoramento, exceto alguns pontos de interrupção.

sys.monitoring.restart_events() → None

  Habilita todos os eventos que foram desabilitados por `sys.monitoring.DISABLE` para todas as ferramentas.

## Registro de funções de retorno de chamada

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

  Registra o chamável func para o event com o tool_id fornecido

  Se outra função de retorno tiver sido registrada para o tool_id e o event fornecidos, ela será cancelada e retornada. Caso contrário, `register_callback()` retorna `None`.

  Levanta um evento de auditoria `sys.monitoring.register_callback` com o argumento `func`.

As funções podem ser canceladas chamando `sys.monitoring.register_callback(tool_id, event, None)`.

As funções de retorno de chamada podem ser registradas e canceladas a qualquer momento.

Os retornos de chamada são chamados apenas uma vez, independentemente de o evento estar ativado global e localmente. Portanto, se um evento puder ser ativado tanto para eventos globais quanto locais pelo seu código, o retorno de chamada precisa ser escrito para lidar com qualquer um dos gatilhos.

### Argumentos da função de retorno de chamada

sys.monitoring.MISSING

  Um valor especial que é passado para uma função de retorno para indicar que não há argumento para a chamada.

Quando ocorre um evento ativo, a função de retorno de chamada registrada é chamada. Funções de retorno retornando um objeto diferente de `DISABLE` vai ter nenhum efeito. Eventos diferentes fornecerão à função de retorno de chamada argumentos diferentes, como segue:

- `PY_START` e `PY_RESUME`:

      func(code: CodeType, instruction_offset: int) -> object

- `PY_RETURN` e `PY_YIELD`:

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

- `CALL`, `C_RAISE` e `C_RETURN` (arg0 pode ser `MISSING` especificamente):

      func(code: CodeType, instruction_offset: int, callable: object, arg0: object) -> object

  code representa o objeto de código onde a chamada está sendo feita, enquanto callable é o objeto que está prestes a ser chamado (e, portanto, acionou o evento). Se não houver argumentos, arg0 é definido como `sys.monitoring.MISSING`.

  Para métodos de instância, callable será o objeto função encontrado na classe com arg0 definido para a instância (ou seja, o argumento `self` para o método).

- `RAISE`, `RERAISE`, `EXCEPTION_HANDLED`, `PY_UNWIND`, `PY_THROW` e `STOP_ITERATION`:

      func(code: CodeType, instruction_offset: int, exception: BaseException) -> object

- `LINE`:

      func(code: CodeType, line_number: int) -> object

- `BRANCH_LEFT`, `BRANCH_RIGHT` e `JUMP`:

      func(code: CodeType, instruction_offset: int, destination_offset: int) -> object

  Observe que o destination_offset é onde o código será executado em seguida.

- `INSTRUCTION`:

      func(code: CodeType, instruction_offset: int) -> object