# How to Use TuiTracingSubscriberLayer to Collect Tracing Events in a TUI App

> Learn to collect tracing events in your TUI app using TuiTracingSubscriberLayer. Integrate with tui-logger for real-time terminal display of tracing data. Enhance your app's observability now.

- Repository: [gin66/tui-logger](https://github.com/gin66/tui-logger)
- Tags: how-to-guide
- Published: 2026-03-02

---

**Register `TuiTracingSubscriberLayer` on a `tracing_subscriber::registry` after calling `tui_logger::init_logger` to forward `tracing` events into the crate's circular buffer for real-time terminal display.**

The `tui-logger` crate provides a `tracing-subscriber` compatible layer that bridges the `tracing` ecosystem with its internal log-based renderer. By enabling the `tracing-support` feature and registering `TuiTracingSubscriberLayer`, any `tracing::info!`, `tracing::debug!`, or other instrumentation events automatically appear in your Ratatui widgets without additional handlers.

## Enable the Tracing Support Feature

To access the integration, add the `tracing-support` feature to your [`Cargo.toml`](https://github.com/gin66/tui-logger/blob/main/Cargo.toml) dependency:

```toml
[dependencies]
tui-logger = { version = "*", features = ["tracing-support"] }
tracing = "0.1"
tracing-subscriber = "0.3"

```

This feature flag exposes `TuiTracingSubscriberLayer`, which is re-exported from [`src/lib.rs`](https://github.com/gin66/tui-logger/blob/main/src/lib.rs) for convenient access.

## Initialize the Logger Before the Registry

The setup requires strict initialization order. You must call `tui_logger::init_logger` **before** any `tracing` events are emitted or the registry is initialized, as noted in the documentation at `src/tracing_subscriber.rs#L74-L78`.

```rust
use tracing_subscriber::prelude::*;
use tui_logger::TuiTracingSubscriberLayer;

fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Must initialize first to create the circular buffer and background thread
    tui_logger::init_logger(tui_logger::LevelFilter::Trace)?;
    
    // Then register the layer on the registry
    tracing_subscriber::registry()
        .with(TuiTracingSubscriberLayer)
        .init();
        
    tracing::info!("Application started");
    Ok(())
}

```

The `init_logger` function, located in [`src/logger/api.rs`](https://github.com/gin66/tui-logger/blob/main/src/logger/api.rs), spawns the background thread that moves events from the hot buffer into the circular buffer that feeds the UI.

## How the Layer Bridges Events to the UI

`TuiTracingSubscriberLayer` implements `tracing_subscriber::Layer` and acts as a converter between the two logging systems. When a `tracing::Event` is emitted, the layer's `on_event` method (defined in `src/tracing_subscriber.rs#L16-L48`) performs three operations:

1. **Extracts metadata** including the target, level, file, line, and module path.
2. **Visits structured fields** using `ToStringVisitor` (`src/tracing_subscriber.rs#L25-L64`) to convert key-value pairs into a formatted string.
3. **Creates a `log::Record`** and forwards it to the global `TUI_LOGGER` singleton via `TUI_LOGGER.log(...)` (`src/tracing_subscriber.rs#L37-L46`).

The `TUI_LOGGER` instance stores the record in a hot buffer, which the background thread drains into a lock-free circular buffer. The `TuiLoggerWidget` (implemented in [`src/widget/standard.rs`](https://github.com/gin66/tui-logger/blob/main/src/widget/standard.rs)) reads from this buffer during each render cycle to display the messages.

## Complete Integration Example

The following example demonstrates the full setup including structured fields and custom targets:

```rust
use tracing_subscriber::prelude::*;
use tui_logger::TuiTracingSubscriberLayer;

fn main() -> Result<(), Box<dyn std::error::Error>> {
    // 1. Initialize the logger (creates TUI_LOGGER global)
    tui_logger::init_logger(tui_logger::LevelFilter::Debug)?;
    
    // 2. Register the tracing layer
    tracing_subscriber::registry()
        .with(TuiTracingSubscriberLayer)
        .init();
    
    // 3. Emit events that automatically appear in the TUI
    tracing::info!(target: "app_startup", "Server initializing");
    tracing::debug!(target: "network", bytes_sent = 1024, "Packet transmitted");
    
    // 4. Run your terminal interface with tui_logger widgets
    // tui_logger::demo::run()?;
    Ok(())
}

```

## Key Source Files and Components

Understanding the repository structure helps debug integration issues:

- **[`src/tracing_subscriber.rs`](https://github.com/gin66/tui-logger/blob/main/src/tracing_subscriber.rs)** – Contains `TuiTracingSubscriberLayer` with the `on_event` handler that performs the `tracing::Event` to `log::Record` conversion.
- **[`src/lib.rs`](https://github.com/gin66/tui-logger/blob/main/src/lib.rs)** – Re-exports the layer at lines 17-22, making it available as `tui_logger::TuiTracingSubscriberLayer`.
- **[`src/logger/api.rs`](https://github.com/gin66/tui-logger/blob/main/src/logger/api.rs)** – Defines `init_logger` and the global `TUI_LOGGER` singleton that receives the bridged events.
- **[`src/widget/standard.rs`](https://github.com/gin66/tui-logger/blob/main/src/widget/standard.rs)** – Implements the default widget that renders buffered log lines from the circular buffer.

## Summary

- **Enable the feature**: Add `tracing-support` to your `tui-logger` dependency to access the layer.
- **Initialize first**: Always call `tui_logger::init_logger` before creating the `tracing_subscriber` registry to ensure the circular buffer exists.
- **Register the layer**: Use `.with(TuiTracingSubscriberLayer)` on your registry to activate the bridge.
- **Emit normally**: Standard `tracing` macros automatically populate the TUI widget through the internal `log` translation layer.

## Frequently Asked Questions

### What happens if I initialize the tracing registry before calling `init_logger`?

The application will panic or silently drop events. The `TUI_LOGGER` global instance must exist before `TuiTracingSubscriberLayer` attempts to forward `log::Record` objects to it, as the layer directly calls `TUI_LOGGER.log()` inside its `on_event` implementation.

### Does `TuiTracingSubscriberLayer` support structured fields and spans?

Yes. The layer uses a `ToStringVisitor` to serialize structured fields from `tracing` events into the message string. While it captures span context via `on_new_span`, the primary output format is a `log::Record` compatible string suitable for the widget's display buffer.

### Can I use `TuiTracingSubscriberLayer` alongside other tracing layers?

Yes. The layer is composable with other `tracing_subscriber::Layer` implementations. You can chain it with formatting layers or filtering layers using the registry's `.with()` method, allowing you to write to both the TUI widget and stdout simultaneously.

### Do I need the `log` crate in my dependencies?

No. While `TuiTracingSubscriberLayer` creates `log::Record` structs internally to interface with `tui-logger`'s buffer, the `log` crate is a dependency of `tui-logger` itself. You only need `tracing` and `tracing-subscriber` in your application code to emit events.