# T-011: `tracing` Log Infrastructure — Subscriber Init, RUST_LOG Filter, Rerun Sink Feature Flag **Type:** Task **Phase:** 0 — Foundation **Autonomy:** `agent:autonomous` — Mechanical wiring, no decisions required. **Stack:** `stack:rust` **Version:** v0.1 **Iteration:** iter-1 **Effort:** XS (1 hour) --- > ⚠️ **Agent Scope:** T-004 already calls `tracing::info!`, `tracing::warn!`, `tracing::error!` throughout `audio/engine.rs`. Right now those calls are silent — no subscriber is registered. T-011 initialises the subscriber so those calls produce output. Add the `rerun-telemetry` Cargo feature as a stub (prints "Rerun sink active" but does no real Rerun work — T-121 owns the real implementation). Nothing else. --- ## Context `tracing` is already a workspace dependency (AMENDMENT-001) and is called throughout `kansas/`. Without a subscriber, every `tracing::info!` call is a no-op and developers get no log output at all — including audio device errors, transport state transitions, and model inference latencies. This task is the one-line initialisation that activates all of it. The `rerun-telemetry` feature flag gates the Rerun SDK dependency. Production builds ship without it (`cargo tauri build` — no Rerun). Development builds opt in with `cargo tauri dev --features rerun-telemetry`. T-121 fills the stub with real Rerun log calls. --- ## Prerequisites - [ ] T-001 merged — workspace `Cargo.toml` with `tracing` and `tracing-subscriber` already listed Verify both are present in `[workspace.dependencies]`. If missing, add: ```toml tracing = { version = "*" } tracing-subscriber = { version = "*", features = ["env-filter", "fmt"] } ``` --- ## Acceptance Criteria - [ ] `cargo tauri dev` prints structured log lines to stdout — at minimum the `[audio]` lines from T-004 - [ ] `RUST_LOG=debug cargo tauri dev` prints debug-level output - [ ] `RUST_LOG=warn cargo tauri dev` shows only warnings and errors - [ ] Without `RUST_LOG` set, default filter is `kansas=info,warn` (kansas at info, everything else at warn) - [ ] `cargo tauri dev --features rerun-telemetry` prints `[logging] Rerun telemetry sink active (stub — see T-121)` and does not crash - [ ] `cargo tauri build` (without `rerun-telemetry`) compiles without error — Rerun SDK is not linked - [ ] `cargo check --workspace` — zero errors - [ ] `cargo clippy --workspace -- -D warnings` — zero warnings --- ## New Cargo Feature Add to `kansas/Cargo.toml`: ```toml [features] default = [] rerun-telemetry = [] # T-121 adds: dep:rerun when this is filled in [dependencies] tracing = { workspace = true } tracing-subscriber = { workspace = true } # rerun dep added by T-121 under rerun-telemetry feature ``` --- ## New File: `kansas/src/logging.rs` ```rust //! Logging infrastructure for the Synesthesia Tauri backend. //! //! Initialise once at startup via [`setup`]. //! Log level controlled by the `RUST_LOG` environment variable. //! //! # Feature: `rerun-telemetry` //! When compiled with `--features rerun-telemetry`, a stub Rerun sink is //! registered alongside the stdout subscriber. T-121 replaces the stub with //! real Rerun log calls. use tracing_subscriber::{ fmt, layer::SubscriberExt, util::SubscriberInitExt, EnvFilter, }; /// Default log filter when `RUST_LOG` is not set. /// - `kansas` crate: INFO and above (our own logs) /// - Everything else: WARN and above (suppress noisy deps) const DEFAULT_FILTER: &str = "kansas=info,warn"; /// Initialise the global tracing subscriber. /// Must be called exactly once, before any `tracing::` calls. /// Panics if called a second time (tracing subscriber is a global singleton). pub fn setup() { let filter = EnvFilter::try_from_default_env() .unwrap_or_else(|_| EnvFilter::new(DEFAULT_FILTER)); let fmt_layer = fmt::layer() .with_target(true) // show module path .with_thread_names(false) // too noisy for audio threads .with_file(false) // file:line in DEBUG only .compact(); let registry = tracing_subscriber::registry() .with(filter) .with(fmt_layer); #[cfg(feature = "rerun-telemetry")] let registry = registry.with(RerunStubLayer); registry.init(); #[cfg(feature = "rerun-telemetry")] tracing::info!("[logging] Rerun telemetry sink active (stub — see T-121)"); tracing::info!("[logging] Tracing initialised — RUST_LOG={}", std::env::var("RUST_LOG").unwrap_or_else(|_| DEFAULT_FILTER.into())); } // ─── Rerun stub layer ───────────────────────────────────────────────────────── #[cfg(feature = "rerun-telemetry")] struct RerunStubLayer; #[cfg(feature = "rerun-telemetry")] impl tracing_subscriber::Layer for RerunStubLayer { // T-121 overrides on_event() to forward structured log data to the Rerun SDK. // Stub: no-op layer that satisfies the trait bound. } ``` --- ## Update `kansas/src/main.rs` Add one line at the top of `main()`, before anything else: ```rust mod logging; // ... other mods fn main() { // MUST be first — initialises global tracing subscriber before any // tracing::* calls in AudioEngine::new(), TransportHandle::new(), etc. logging::setup(); let audio_engine = AudioEngine::new() .expect("Failed to initialise audio engine"); tauri::Builder::default() // ... ``` --- ## Add `logging` Module to `kansas/src/lib.rs` ```rust pub mod logging; ``` --- ## Implementation Notes ### Why `compact()` not `pretty()` `pretty()` emits multi-line ANSI output. In a terminal it looks great; in a Windows file redirect or CI log it produces garbled escape codes and hard-to-grep output. `compact()` gives single-line structured output readable in both. ### `tracing::instrument` for hot paths Do **not** add `#[tracing::instrument]` to the audio callback or the tick loop — these fire 200+ times per second and the span overhead accumulates. Reserve `#[instrument]` for IPC command handlers and one-shot initialisation paths. T-011 does not add any `#[instrument]` attributes; that is left to individual task authors. ### The `RerunStubLayer` no-op trait impl `tracing_subscriber::Layer` has default implementations for all methods. The empty `impl` is valid Rust — it compiles to a zero-cost abstraction that adds no overhead when `rerun-telemetry` is disabled (the feature gates the entire struct out of the binary). When T-121 arrives it fills in `fn on_event(...)` to forward log fields to the Rerun SDK. ### Log output format After T-011, `cargo tauri dev` produces lines like: ``` 2026-03-19T18:45:01.234Z INFO kansas::logging: [logging] Tracing initialised — RUST_LOG=kansas=info,warn 2026-03-19T18:45:01.235Z INFO kansas::audio::engine: [audio] Output: Speakers (Realtek) | 48000Hz | 2ch 2026-03-19T18:45:01.236Z INFO kansas::audio::engine: [audio] Input: Microphone (USB) | 48000Hz | 2ch ``` --- ## Testing ```bash # Default filter — should see INFO from kansas, WARN from deps cargo tauri dev # Debug filter — verbose output RUST_LOG=debug cargo tauri dev # Warn only — mostly silent RUST_LOG=warn cargo tauri dev # Rerun stub cargo tauri dev --features rerun-telemetry # Expected line: [logging] Rerun telemetry sink active (stub — see T-121) # Release build must NOT include rerun cargo tauri build # Verify: ldd/dumpbin on the .exe shows no rerun .dll ``` --- ## GitHub CLI ```bash gh issue create \ --title "T-011: tracing log infrastructure — subscriber init, RUST_LOG filter, Rerun sink stub" \ --label "type:task,stack:rust,agent:autonomous,priority:high,status:ready,day:1" \ --body-file T-011.md ``` --- **Parent:** GENESIS **Blocks:** T-121 (fills `RerunStubLayer::on_event` with real Rerun calls) **Blocked By:** T-001 **Version:** v0.1 · **Iteration:** iter-1 · **Effort:** XS (1 hour)