Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

追蹤

為了效能而撰寫擴充模組的 Python 專案,可能會想使用 Rust 的 tracing 生態系 來了解擴充模組的效能表現。

本節介紹幾個提供此能力的軟體箱。它們建立在 tracing_subscriber 之上,並需要同時修改 Python 與 Rust 程式碼來整合。請注意每個擴充模組都必須設定自己的 tracing 整合;一個擴充模組無法看到另一個模組的 tracing 資料。

pyo3-tracing-subscriber文件

pyo3-tracing-subscriber 提供 Python 專案設定 tracing_subscriber 的方式,並暴露幾個 tracing_subscriber layer:

  • tracing_subscriber::fmt:輸出易讀格式到檔案或 stdout
  • opentelemetry-stdout:輸出 OTLP 到檔案或 stdout
  • opentelemetry-otlp:輸出 OTLP 到 OTLP 端點

擴充模組必須呼叫 pyo3_tracing_subscriber::add_submodule 來導出設定與初始化 tracing 所需的 Python 類別。

在 Python 端,使用 Tracing 內容管理器來初始化 tracing,並在其區塊內執行 Rust 程式碼。Tracing 需要一個描述使用哪些 layer 的 GlobalTracingConfig 實例。

範例程式碼請見 crates.io 的 README

pyo3-python-tracing-subscriber文件

名稱相近的 pyo3-python-tracing-subscriber 在 Rust 中實作一個 shim,將 tracing 資料轉送到由 Python 定義並傳入的 Layer 實作。

擴充模組可用多種方式整合 pyo3-python-tracing-subscriber,其中一個簡單做法可能如下:

#[tracing::instrument]
#[pyfunction]
fn fibonacci(index: usize, use_memoized: bool) -> PyResult<usize> {
    // ...
}

#[pyfunction]
pub fn initialize_tracing(py_impl: Bound<'_, PyAny>) {
    tracing_subscriber::registry()
        .with(pyo3_python_tracing_subscriber::PythonCallbackLayerBridge::new(py_impl))
        .init();
}

擴充模組必須提供某種方式,讓 Python 傳入一個或多個實作了 Layer 介面 的 Python 物件。接著應使用這些物件建立 pyo3_python_tracing_subscriber::PythonCallbackLayerBridge 實例,並如上所示初始化 tracing_subscriber

Python 物件實作的是改良版的 Layer 介面:

  • on_new_span() 可回傳狀態,該狀態會儲存在 Rust span 中
  • 其他回呼會以額外的位置參數取得該狀態

一個假的 Layer 實作可能如下:

import rust_extension

class MyPythonLayer:
    def __init__(self):
        pass

    # `on_new_span` 可以回傳某些狀態
    def on_new_span(self, span_attrs: str, span_id: str) -> int:
        print(f"[on_new_span]: {span_attrs} | {span_id}")
        return random.randint(1, 1000)

    # 來自 `on_new_span` 的狀態會傳回其他特徵方法
    def on_event(self, event: str, state: int):
        print(f"[on_event]: {event} | {state}")

    def on_close(self, span_id: str, state: int):
        print(f"[on_close]: {span_id} | {state}")

    def on_record(self, span_id: str, values: str, state: int):
        print(f"[on_record]: {span_id} | {values} | {state}")

def main():
    rust_extension.initialize_tracing(MyPythonLayer())

    print("10th fibonacci number: ", rust_extension.fibonacci(10, True))

pyo3-python-tracing-subscriber 提供可運作的範例,展示 Rust 與 Python 端的整合方式。