# PyO3 Tracing Subscriber
## Background
### What this is
`pyo3_tracing_subscriber` provides a `PyModule` that can be added to upstream `pyo3` extension modules in order to support the configuration and initialization of Rust tracing subscribers from Python.
### What this is not
* Any initialized tracing subscriber imported from your upstream package will _not_ collect traces from any other `pyo3` extension module. In other words, any `pyo3` extension module will need to separately export tracing configuration and context managers, which in turn must be separately initialized in order to capture Rust traces from respective `pyo3` extension modules.
* Currently, only three tracing subcriber layers are supported:
* `tracing_subscriber::fmt` which writes traces to file (or stdout) in a human readable format.
* `opentelemetry-stdout` which writes traces to file (or stdout) in OTLP format. Available only with the `layer-otel-otlp-file` feature.
* `opentelemetry-otlp` which sends traces to an OpenTelemetry OTLP endpoint. Available only with the `layer-otel-otlp` feature.
* This does not propagate OpenTelemetry contexts from Python into Rust (or vice versa). Use the `pyo3-opentelemetry` crate for that feature.
## Usage
> For a complete functioning example, see the `examples/pyo3-opentelemetry-lib/src/lib.rs` example within this crate's repository.
Given a `pyo3` extension module named "my_module" that would like to expose the tracing subscriber configuration and context manager classes from "my_module._tracing_subscriber", from Rust:
```rust
use pyo3::prelude::*;
#[pymodule]
fn my_module(py: Python, m: &PyModule) -> PyResult<()> {
// Add your own Python classes, functions and modules.
pyo3_tracing_subscriber::add_submodule(
"my_module",
"_tracing_subscriber",
py,
m,
)?;
Ok(())
}
```
Then a user could initialize a tracing subscriber that logged to stdout from Python:
```python
import my_module
from my_module._tracing_subscriber import (
GlobalTracingConfig,
SimpleConfig,
Tracing,
subscriber,
)
from pyo3_opentelemetry_lib._tracing_subscriber.layers import file
def main():
tracing_configuration = GlobalTracingConfig(
export_process=SimpleConfig(
subscriber=subscriber.Config(
layer=file.Config()
)
)
)
with Tracing(config=config):
result = my_module.example_function()
my_module.other_example_function(result)
if __name__ == '__main__':
main()
```
### Building Python Stub Files
This crate provides a convenient method for adding stub files to your Python source code with the `stubs` feature.
Given a `pyo3` extension module named "my_module" that uses the `pyo3-tracing-subscriber` crate to expose tracing subscriber configuration and context manager classes from "my_module._tracing_subscriber", in the upstream `build.rs` file:
```rust
use pyo3_tracing_subscriber_stubs::write_stub_files;
fn main() {
let target_dir = std::path::Path::new("./my_module/_tracing_subscriber");
std::fs::remove_dir_all(target_dir).unwrap();
write_stub_files(
"my_module",
"_tracing_subscriber",
target_dir,
true, // layer_otel_otlp_file feature enabled
true, // layer_otel_otlp feature enabled
)
.unwrap();
}
```