https://github.com/getsentry/pyo3-python-tracing-subscriber
A `tracing_subscriber` layer that forwards data to a handler written in Python.
https://github.com/getsentry/pyo3-python-tracing-subscriber
tag-non-production
Last synced: 3 months ago
JSON representation
A `tracing_subscriber` layer that forwards data to a handler written in Python.
- Host: GitHub
- URL: https://github.com/getsentry/pyo3-python-tracing-subscriber
- Owner: getsentry
- License: mit
- Created: 2024-10-24T21:17:50.000Z (8 months ago)
- Default Branch: main
- Last Pushed: 2024-12-17T20:58:35.000Z (6 months ago)
- Last Synced: 2025-03-22T06:47:10.744Z (3 months ago)
- Topics: tag-non-production
- Language: Rust
- Homepage: https://crates.io/crates/pyo3-python-tracing-subscriber
- Size: 40 KB
- Stars: 0
- Watchers: 27
- Forks: 2
- Open Issues: 1
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- License: LICENSE
Awesome Lists containing this project
README
# `pyo3-python-tracing-subscriber`

[](https://codecov.io/gh/getsentry/pyo3-python-tracing-subscriber)
[](https://crates.io/crates/pyo3-python-tracing-subscriber)
[](https://docs.rs/pyo3-python-tracing-subscriber)A `tracing_subscriber` layer for native extensions that forwards `tracing` data to a Python handler.
See the `demo` folder for working examples.
### Usage
Native extensions that use `tracing` can expose a function to Python to initialize `tracing`:
```rust
#[tracing::instrument]
#[pyfunction]
fn fibonacci(index: usize, use_memoized: bool) -> PyResult {
// ...
}#[pyfunction]
pub fn initialize_tracing(py_impl: Bound<'_, PyAny>) {
tracing_subscriber::registry()
.with(pyo3_python_tracing_subscriber::PythonCallbackLayerBridge::new(py_impl))
.init();
}
```Python code can pass an implementation of `tracing_subscriber::layer::Layer` (but slightly different) into `initialize_tracing` and then future calls to instrumented Rust functions will forward tracing data to the Python layer.
```python
import rust_extensionclass MyPythonLayer:
def __init__(self):
pass# `on_new_span` can return some state
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)# The state from `on_new_span` is passed back into other trait methods
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))
```Only a subset of `Layer` trait methods are currently forwarded to Python.
### Native extension quirks
Native extensions are self-contained with their own global variables and copies of dependencies. Because of this:
- Each native extension needs to initialize `tracing` separately to forward its data to Python
- `pyo3-python-tracing-subscriber` itself is not a native extension and can't be used from Python
- This is because the compiled code in its own native extension wouldn't be guaranteed to be ABI-compatible with the compiled code included in other native extensions that want to use it
- If `pyo3` + `tracing_subscriber` support trait objects then this can change### Contributing
Test with:
```
$ cargo test
```