Tauri Plugin
Add the plugin crate to your Tauri app:
[dependencies]tauri-plugin-auditaur = "0.1.3"tracing = "0.1"tracing-subscriber = "0.3"Register the plugin and, if you want backend tracing, install the tracing layer before starting Tauri:
use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt};
fn main() { tracing_subscriber::registry() .with(tauri_plugin_auditaur::tracing_layer()) .init();
tauri::Builder::default() .plugin( tauri_plugin_auditaur::Builder::new() .service_name("my-tauri-app") .session_name("dev") .redact_defaults(true) .max_session_bytes(256 * 1024 * 1024) .build(), ) .run(tauri::generate_context!()) .expect("failed to run app");}The plugin creates the SQLite session database, writes a discovery file, receives frontend telemetry batches through export_otel_batch, applies recursive redaction, records Rust tracing events/spans, stores the optional session name, and applies best-effort retention after frontend batches.
To continue frontend invoke() traces into backend command spans, use auditaur_command on app-owned Tauri commands:
#[tauri_plugin_auditaur::auditaur_command]fn load_user(id: String) -> Result<String, String> { tracing::info!(user.id = %id, "loading user"); Ok(id)}The frontend wrapper sends W3C traceparent in Tauri invoke request headers and also sends the older reserved auditaurTraceContext argument for compatibility. auditaur_command wraps #[tauri::command], injects both IPC carriers, prefers the request header, falls back to the reserved argument, and adds the tracing::instrument fields needed for Auditaur’s tracing layer, so the backend command span is parented to the frontend invoke span without command-name or timestamp heuristics. Existing tracing options can be passed through, for example #[tauri_plugin_auditaur::auditaur_command(err)] or #[tauri_plugin_auditaur::auditaur_command(skip(app))].
If you need to keep an explicit #[tauri::command], use the lower-level compatibility helper:
use tauri_plugin_auditaur::IpcTraceContext;
#[tauri::command]#[tauri_plugin_auditaur::instrument_ipc(err)]fn load_user_legacy( id: String, auditaur_trace_context: Option<IpcTraceContext>,) -> Result<String, String> { tracing::info!(user.id = %id, "loading user"); Ok(id)}An expected healthy invoke trace has:
| Row | Expected shape |
|---|---|
| Frontend span | name = "tauri.invoke load_user", kind = "client", and a generated trace_id / span_id. |
| IPC row | command = "load_user" with the same trace_id and span_id as the frontend span. |
| Backend span | Same trace_id, parent_span_id equal to the frontend invoke span id, and a traceparent attribute. |
If auditaur explain --trace <id> --json sees a frontend invoke span without a backend child span, it reports a missing backend trace continuation finding and suggests adding auditaur_command or instrument_ipc.
App integration tests can assert the same shape after exercising a command:
tauri_plugin_auditaur::test_helpers::assert_trace_stitched( "path/to/telemetry.sqlite", "load_user",);Add auditaur:default to the app capability so the frontend package can call the plugin command:
{ "permissions": ["core:default", "auditaur:default"]}The collector is development-first. Release builds are blocked unless allow_release_builds(true) is explicitly set after reviewing what the app emits and how diagnostics will be handled.