sys.monitoring — Überwachung von Ausführungsereignissen

Hinzugefügt in Version 3.12.


Hinweis

sys.monitoring ist ein Namensraum innerhalb des sys Moduls, kein eigenständiges Modul, daher ist es nicht notwendig, import sys.monitoring zu verwenden. Importieren Sie einfach import sys und verwenden Sie dann sys.monitoring.

Dieser Namensraum bietet Zugriff auf die Funktionen und Konstanten, die zur Aktivierung und Steuerung der Ereignisüberwachung erforderlich sind.

Während Programme ausgeführt werden, treten Ereignisse auf, die für Tools zur Überwachung der Ausführung von Interesse sein können. Der Namensraum sys.monitoring bietet Mittel, um Rückruffunktionen zu erhalten, wenn interessante Ereignisse auftreten.

Die Überwachungs-API besteht aus drei Komponenten

Tool-Bezeichner

Ein Tool-Bezeichner ist eine Ganzzahl und der zugehörige Name. Tool-Bezeichner werden verwendet, um zu verhindern, dass Tools sich gegenseitig stören, und um mehreren Tools die gleichzeitige Ausführung zu ermöglichen. Derzeit sind Tools vollständig unabhängig und können nicht dazu verwendet werden, sich gegenseitig zu überwachen. Diese Einschränkung kann in Zukunft aufgehoben werden.

Bevor Ereignisse registriert oder aktiviert werden, sollte ein Tool einen Bezeichner wählen. Bezeichner sind Ganzzahlen im Bereich von 0 bis einschließlich 5.

Registrierung und Verwendung von Tools

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

Muss aufgerufen werden, bevor tool_id verwendet werden kann. tool_id muss im Bereich von 0 bis einschließlich 5 liegen. Löst einen ValueError aus, wenn tool_id bereits verwendet wird.

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

Registriert alle Ereignisse und Rückruffunktionen ab, die mit tool_id verknüpft sind.

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

Sollte aufgerufen werden, wenn ein Tool tool_id nicht mehr benötigt. Ruft clear_tool_id() auf, bevor tool_id freigegeben wird.

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

Gibt den Namen des Tools zurück, wenn tool_id verwendet wird, andernfalls gibt sie None zurück. tool_id muss im Bereich von 0 bis einschließlich 5 liegen.

Alle IDs werden von der VM in Bezug auf Ereignisse gleich behandelt, aber die folgenden IDs sind vordefiniert, um die Zusammenarbeit von Tools zu erleichtern

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

Ereignisse

Die folgenden Ereignisse werden unterstützt

sys.monitoring.events.BRANCH_LEFT

Ein bedingter Sprung geht nach links.

Es liegt am Tool zu entscheiden, wie "linke" und "rechte" Zweige dargestellt werden. Es gibt keine Garantie, welcher Zweig "links" und welcher "rechts" ist, außer dass dies für die Dauer des Programms konsistent sein wird.

sys.monitoring.events.BRANCH_RIGHT

Ein bedingter Sprung geht nach rechts.

sys.monitoring.events.CALL

Ein Aufruf im Python-Code (Ereignis tritt vor dem Aufruf auf).

sys.monitoring.events.C_RAISE

Eine Ausnahme, die von einer beliebigen aufrufbaren Funktion ausgelöst wird, mit Ausnahme von Python-Funktionen (Ereignis tritt nach dem Verlassen auf).

sys.monitoring.events.C_RETURN

Rückkehr von einer beliebigen aufrufbaren Funktion, mit Ausnahme von Python-Funktionen (Ereignis tritt nach der Rückkehr auf).

sys.monitoring.events.EXCEPTION_HANDLED

Eine Ausnahme wird behandelt.

sys.monitoring.events.INSTRUCTION

Eine VM-Instruktion wird ausgeführt.

sys.monitoring.events.JUMP

Ein unbedingter Sprung im Kontrollflussgraphen wird durchgeführt.

sys.monitoring.events.LINE

Eine Anweisung wird ausgeführt, die eine andere Zeilennummer als die vorherige Anweisung hat.

sys.monitoring.events.PY_RESUME

Wiederaufnahme einer Python-Funktion (für Generator- und Coroutine-Funktionen), außer bei throw() Aufrufen.

sys.monitoring.events.PY_RETURN

Rückkehr aus einer Python-Funktion (tritt unmittelbar vor der Rückkehr auf, der Frame des Aufgerufenen befindet sich auf dem Stapel).

sys.monitoring.events.PY_START

Start einer Python-Funktion (tritt unmittelbar nach dem Aufruf auf, der Frame des Aufgerufenen befindet sich auf dem Stapel)

sys.monitoring.events.PY_THROW

Eine Python-Funktion wird durch einen throw() Aufruf wieder aufgenommen.

sys.monitoring.events.PY_UNWIND

Verlassen einer Python-Funktion während des Exception-Unwindings. Dies schließt Ausnahmen ein, die direkt innerhalb der Funktion ausgelöst und weiter propagiert werden.

sys.monitoring.events.PY_YIELD

Yield aus einer Python-Funktion (tritt unmittelbar vor dem Yield auf, der Frame des Aufgerufenen befindet sich auf dem Stapel).

sys.monitoring.events.RAISE

Eine Ausnahme wird ausgelöst, außer solchen, die ein STOP_ITERATION Ereignis verursachen.

sys.monitoring.events.RERAISE

Eine Ausnahme wird erneut ausgelöst, z.B. am Ende eines finally Blocks.

sys.monitoring.events.STOP_ITERATION

Eine künstliche StopIteration wird ausgelöst; siehe das STOP_ITERATION-Ereignis.

Zukünftig können weitere Ereignisse hinzugefügt werden.

Diese Ereignisse sind Attribute des Namensraums sys.monitoring.events. Jedes Ereignis wird durch eine Zweierpotenz-Ganzzahlkonstante dargestellt. Um eine Menge von Ereignissen zu definieren, werden die einzelnen Ereignisse einfach durch bitweises OR zusammengefügt. Um beispielsweise sowohl PY_RETURN als auch PY_START Ereignisse anzugeben, verwenden Sie den Ausdruck PY_RETURN | PY_START.

sys.monitoring.events.NO_EVENTS

Ein Alias für 0, damit Benutzer explizite Vergleiche wie folgt durchführen können:

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

Das Setzen dieses Ereignisses deaktiviert alle Ereignisse.

Lokale Ereignisse

Lokale Ereignisse sind mit der normalen Ausführung des Programms verbunden und treten an klar definierten Stellen auf. Alle lokalen Ereignisse können deaktiviert werden. Die lokalen Ereignisse sind:

Veraltetes Ereignis

  • BRANCH

Das Ereignis BRANCH ist in 3.14 veraltet. Die Verwendung von BRANCH_LEFT und BRANCH_RIGHT Ereignissen bietet eine deutlich bessere Leistung, da sie unabhängig voneinander deaktiviert werden können.

Ancillary-Ereignisse

Ancillary-Ereignisse können wie andere Ereignisse überwacht werden, werden aber von einem anderen Ereignis gesteuert.

Die Ereignisse C_RETURN und C_RAISE werden vom CALL Ereignis gesteuert. C_RETURN und C_RAISE Ereignisse werden nur dann ausgelöst, wenn das entsprechende CALL Ereignis überwacht wird.

Andere Ereignisse

Andere Ereignisse sind nicht unbedingt an eine bestimmte Stelle im Programm gebunden und können nicht einzeln deaktiviert werden.

Die anderen Ereignisse, die überwacht werden können, sind:

Das STOP_ITERATION-Ereignis

PEP 380 legt fest, dass eine StopIteration Ausnahme ausgelöst wird, wenn ein Wert aus einem Generator oder Coroutine zurückgegeben wird. Dies ist jedoch eine sehr ineffiziente Methode, einen Wert zurückzugeben, daher lösen einige Python-Implementierungen, insbesondere CPython 3.12+, keine Ausnahme aus, es sei denn, sie wäre für anderen Code sichtbar.

Um Tools die Überwachung echter Ausnahmen zu ermöglichen, ohne Generatoren und Coroutinen zu verlangsamen, wird das Ereignis STOP_ITERATION bereitgestellt. STOP_ITERATION kann lokal deaktiviert werden, im Gegensatz zu RAISE.

Beachten Sie, dass das Ereignis STOP_ITERATION und das Ereignis RAISE für eine StopIteration Ausnahme äquivalent sind und als austauschbar behandelt werden, wenn Ereignisse generiert werden. Implementierungen bevorzugen STOP_ITERATION aus Leistungsgründen, können aber ein RAISE Ereignis mit einer StopIteration generieren.

Ereignisse ein- und ausschalten

Um ein Ereignis zu überwachen, muss es aktiviert und eine entsprechende Rückruffunktion registriert werden. Ereignisse können global und/oder für ein bestimmtes Code-Objekt ein- oder ausgeschaltet werden. Ein Ereignis wird nur einmal ausgelöst, auch wenn es sowohl global als auch lokal aktiviert ist.

Ereignisse global setzen

Ereignisse können global gesteuert werden, indem die Menge der überwachten Ereignisse geändert wird.

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

Gibt die int zurück, die alle aktiven Ereignisse repräsentiert.

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

Aktiviert alle Ereignisse, die in event_set gesetzt sind. Löst einen ValueError aus, wenn tool_id nicht verwendet wird.

Standardmäßig sind keine Ereignisse aktiv.

Ereignisse pro Code-Objekt

Ereignisse können auch pro Code-Objekt gesteuert werden. Die unten definierten Funktionen, die einen types.CodeType akzeptieren, sollten darauf vorbereitet sein, ein ähnliches Objekt von Funktionen zu akzeptieren, die nicht in Python definiert sind (siehe Monitoring C API).

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

Gibt alle lokalen Ereignisse für code zurück.

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

Aktiviert alle lokalen Ereignisse für code, die in event_set gesetzt sind. Löst einen ValueError aus, wenn tool_id nicht verwendet wird.

Ereignisse deaktivieren

sys.monitoring.DISABLE

Ein spezieller Wert, der von einer Rückruffunktion zurückgegeben werden kann, um Ereignisse für den aktuellen Code-Ort zu deaktivieren.

Lokale Ereignisse können für einen bestimmten Code-Ort deaktiviert werden, indem sys.monitoring.DISABLE aus einer Rückruffunktion zurückgegeben wird. Dies ändert nicht, welche Ereignisse gesetzt sind, oder andere Code-Orte für dasselbe Ereignis.

Die Deaktivierung von Ereignissen für bestimmte Orte ist für eine hochleistungsfähige Überwachung sehr wichtig. Ein Programm kann beispielsweise ohne Overhead unter einem Debugger ausgeführt werden, wenn der Debugger die gesamte Überwachung bis auf wenige Breakpoints deaktiviert.

sys.monitoring.restart_events() None

Aktiviert alle Ereignisse, die von sys.monitoring.DISABLE für alle Tools deaktiviert wurden.

Registrierung von Rückruffunktionen

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

Registriert die aufrufbare Funktion func für das event mit der gegebenen tool_id.

Wenn eine andere Rückruffunktion für die gegebene tool_id und das event registriert war, wird diese abgemeldet und zurückgegeben. Andernfalls gibt register_callback() None zurück.

Löst ein Audit-Ereignis sys.monitoring.register_callback mit dem Argument func aus.

Funktionen können durch Aufruf von sys.monitoring.register_callback(tool_id, event, None) abgemeldet werden.

Rückruffunktionen können jederzeit registriert und abgemeldet werden.

Rückruffunktionen werden nur einmal aufgerufen, unabhängig davon, ob das Ereignis sowohl global als auch lokal aktiviert ist. Daher muss die Rückruffunktion so geschrieben sein, dass sie beide Auslöser verarbeiten kann.

Argumente der Rückruffunktion

sys.monitoring.MISSING

Ein spezieller Wert, der an eine Rückruffunktion übergeben wird, um anzuzeigen, dass die Funktion keine Argumente hat.

Wenn ein aktives Ereignis auftritt, wird die registrierte Rückruffunktion aufgerufen. Rückruffunktionen, die ein anderes Objekt als DISABLE zurückgeben, haben keine Auswirkungen. Verschiedene Ereignisse übergeben der Rückruffunktion unterschiedliche Argumente, wie folgt:

  • PY_START und PY_RESUME

    func(code: CodeType, instruction_offset: int) -> object
    
  • PY_RETURN und PY_YIELD

    func(code: CodeType, instruction_offset: int, retval: object) -> object
    
  • CALL, C_RAISE und C_RETURN (arg0 kann spezifisch MISSING sein)

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

    code repräsentiert das Code-Objekt, an dem der Aufruf getätigt wird, während callable das Objekt ist, das aufgerufen werden soll (und somit das Ereignis ausgelöst hat). Wenn keine Argumente vorhanden sind, wird arg0 auf MISSING gesetzt.

    Bei Instanzmethoden ist callable das Funktions-Objekt, wie es auf der Klasse gefunden wird, mit arg0 auf die Instanz gesetzt (d.h. das self-Argument der Methode).

  • RAISE, RERAISE, EXCEPTION_HANDLED, PY_UNWIND, PY_THROW und STOP_ITERATION

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

    func(code: CodeType, line_number: int) -> object
    
  • BRANCH_LEFT, BRANCH_RIGHT und JUMP

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

    Beachten Sie, dass destination_offset der Ort ist, an dem der Code als nächstes ausgeführt wird.

  • INSTRUCTION:

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