# How to Integrate tui-logger with slog Using TuiSlogDrain

> Seamlessly integrate tui-logger with slog using TuiSlogDrain. Enable slog-support, initialize the logger, and bridge records to your terminal UI for enhanced debugging.

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

---

**Enable the `slog-support` feature in your [`Cargo.toml`](https://github.com/gin66/tui-logger/blob/main/Cargo.toml), initialize the global tui-logger runtime with `init_logger()`, then create a `TuiSlogDrain` via `slog_drain()` to bridge slog records into the terminal UI widgets.**

The `gin66/tui-logger` crate provides a terminal UI widget for viewing and filtering logs in real time. When you need to integrate it with the structured **slog** ecosystem, the crate exposes a dedicated `TuiSlogDrain` type that acts as a bridge. This allows you to retain slog's structured logging and key-value pairs while gaining the interactive display capabilities of tui-logger.

## Enable the slog-support Feature

Add `tui-logger` to your [`Cargo.toml`](https://github.com/gin66/tui-logger/blob/main/Cargo.toml) with the `slog-support` feature enabled:

```toml
tui-logger = { version = "0.18", features = ["slog-support"] }

```

This feature flag gates the [`src/slog.rs`](https://github.com/gin66/tui-logger/blob/main/src/slog.rs) module, which contains the `TuiSlogDrain` implementation and the `slog_drain()` constructor. Without this feature, the slog integration code is excluded from the build.

## Initialize the tui-logger Runtime

Before any slog records are emitted, you must start the **tui-logger** runtime. The simplest approach is to call the initialization functions exposed in [`src/lib.rs`](https://github.com/gin66/tui-logger/blob/main/src/lib.rs):

```rust
tui_logger::init_logger(log::LevelFilter::Trace).expect("Failed to init tui-logger");
tui_logger::set_default_level(log::LevelFilter::Trace);

```

This creates the global `TUI_LOGGER` instance and prepares the circular buffer that stores incoming log records. If you skip this step, the `TuiSlogDrain` will have no destination for its converted records.

## Create the TuiSlogDrain and slog Logger

Once the runtime is initialized, create the drain and wire it into a slog logger:

```rust
use slog::{o, Drain, Logger};
use tui_logger::slog_drain;  // Re-exported from src/lib.rs when feature is enabled

let drain = slog_drain().fuse();      // Creates a TuiSlogDrain
let log = Logger::root(drain, o!());  // Standard slog root logger

```

The `slog_drain()` function returns a fresh `TuiSlogDrain` instance defined in [`src/slog.rs`](https://github.com/gin66/tui-logger/blob/main/src/slog.rs). This type implements the `slog::Drain` trait, allowing you to fuse it with other drains or use it in composed logging pipelines. The `.fuse()` method handles error conversion to ensure the drain never returns an error at runtime.

## Emit Log Records and Render the UI

With the logger configured, use standard slog macros to emit structured records:

```rust
use slog::{info, error, debug, trace, warn};

info!(log, "Application started");
debug!(log, "Debug details"; "user_id" => 42);
warn!(log, "Potential problem detected");
error!(log, "Something went terribly wrong");
trace!(log, "Trace message with extra kv"; "payload" => ?some_data);

```

The conversion logic—mapping slog `Level` to `log::Level`, extracting the target module, and constructing a `log::Record`—is implemented in the `log` method of `TuiSlogDrain` at lines 88-116 of [`src/slog.rs`](https://github.com/gin66/tui-logger/blob/main/src/slog.rs). Each record is forwarded to the global `TUI_LOGGER` instance, which stores it in a circular buffer.

Finally, render the logs using a widget in your terminal UI loop:

```rust
use tui_logger::TuiLoggerSmartWidget;

terminal.draw(|f| {
    let size = f.size();
    let widget = TuiLoggerSmartWidget::default()
        .state(&mut tui_logger::TuiWidgetState::new());
    f.render_widget(widget, size);
})?;

```

The `TuiLoggerSmartWidget` (defined in [`src/widget/smart.rs`](https://github.com/gin66/tui-logger/blob/main/src/widget/smart.rs)) automatically displays the slog records that have been drained into the buffer.

## Complete Integration Example

Below is a minimal, runnable program demonstrating the full integration:

```rust
// Cargo.toml dependencies:
// tui-logger = { version = "0.18", features = ["slog-support", "termion"] }
// slog = "2.7"
// termion = "2.0"

use slog::{o, Drain, Logger, info, warn, error};
use tui_logger::{slog_drain, init_logger, set_default_level};
use std::io;
use termion::raw::IntoRawMode;
use tui::{backend::TermionBackend, Terminal};

fn main() -> Result<(), io::Error> {
    // Initialize the global tui-logger
    init_logger(log::LevelFilter::Trace).expect("init_logger failed");
    set_default_level(log::LevelFilter::Trace);

    // Build a slog logger that drains into tui-logger
    let drain = slog_drain().fuse();
    let log = Logger::root(drain, o!());

    // Emit slog records
    info!(log, "Hello from slog");
    warn!(log, "A warning"; "code" => 404);
    error!(log, "An error occurred");

    // Set up a termion UI to display the widget
    let stdout = io::stdout().into_raw_mode().unwrap();
    let backend = TermionBackend::new(stdout);
    let mut terminal = Terminal::new(backend).unwrap();

    terminal.draw(|f| {
        let size = f.size();
        let widget = tui_logger::TuiLoggerSmartWidget::default()
            .state(&mut tui_logger::TuiWidgetState::new());
        f.render_widget(widget, size);
    })?;

    Ok(())
}

```

A more comprehensive demonstration is available in the repository at `examples/slog.rs_outdated`, which shows advanced usage with the termion backend and real-time UI updates.

## Summary

- **Enable the `slog-support` feature** in [`Cargo.toml`](https://github.com/gin66/tui-logger/blob/main/Cargo.toml) to access `TuiSlogDrain` in [`src/slog.rs`](https://github.com/gin66/tui-logger/blob/main/src/slog.rs)
- **Call `init_logger()`** before creating the slog drain to initialize the global logger state
- **Use `slog_drain()`** to obtain a drain implementing `slog::Drain`, then fuse it and pass it to `Logger::root`
- **Emit logs** using standard slog macros; the drain converts each record to a `log::Record` and forwards it to the circular buffer
- **Render the UI** with `TuiLoggerSmartWidget` or `TuiLoggerWidget` to view the structured log stream

## Frequently Asked Questions

### Do I need to enable a specific feature to use TuiSlogDrain?

Yes, you must enable the `slog-support` feature when adding `tui-logger` to your dependencies. This feature gates the [`src/slog.rs`](https://github.com/gin66/tui-logger/blob/main/src/slog.rs) module, which contains the `TuiSlogDrain` struct and the `slog_drain()` function. Without it, these items are not compiled or exported from the crate.

### Can I combine TuiSlogDrain with other slog drains?

Absolutely. `TuiSlogDrain` implements the standard `slog::Drain` trait, so you can fuse it with other drains or include it in a drain chain. The `.fuse()` method is standard slog practice for error handling, allowing you to compose the drain with async wrappers, duplicate outputs, or level filters without breaking the pipeline.

### How does tui-logger handle slog's structured key-value pairs?

The integration preserves structured data. In [`src/slog.rs`](https://github.com/gin66/tui-logger/blob/main/src/slog.rs), the `log` method (lines 88-116) extracts the message, target, and level from the slog record, then constructs a standard `log::Record` that includes the formatted key-value pairs. These records are stored in the internal circular buffer and displayed by the UI widgets with full formatting.

### Where can I find a complete working example of this integration?

The `gin66/tui-logger` repository includes a full demonstration in `examples/slog.rs_outdated`. This example illustrates feature-gated imports, proper logger initialization, creating the drain, and wiring everything into a termion-based terminal application with interactive log viewing.