Crate lazylog_framework

Crate lazylog_framework 

Source
Expand description

§lazylog-framework

A powerful, extensible framework for building terminal-based log viewers with vim-like navigation and real-time monitoring capabilities.

§Overview

lazylog-framework provides a provider-based architecture that separates log acquisition from display. You implement the LogProvider and LogParser traits to define your log source and formatting, and the framework handles all the TUI rendering, navigation, filtering, and user interaction.

§Core Concepts

§Provider Pattern

The framework uses a two-trait system:

  • LogProvider: Acquires raw log data from any source (files, sockets, APIs, etc.)
  • LogParser: Parses raw strings into LogItems and formats them for display

This separation allows you to:

  • Reuse providers with different parsers
  • Reuse parsers with different providers
  • Easily test parsing logic independently

§Ring Buffer

Logs flow through a lock-free ring buffer with configurable capacity (default: 16K items). When full, old logs are automatically discarded to prevent unbounded memory growth.

§Non-blocking Architecture

The provider runs in a background thread, polling at configurable intervals (default: 100ms). The main thread handles UI rendering and user input, keeping the interface responsive.

§Quick Start

use lazylog_framework::{LogProvider, LogParser, LogItem, start_with_provider};
use anyhow::Result;
use std::sync::Arc;

// 1. implement LogProvider for your log source
struct MyLogProvider {
    // your state here (file handle, socket, etc.)
}

impl LogProvider for MyLogProvider {
    fn start(&mut self) -> Result<()> {
        // setup resources (open files, connect to streams, etc.)
        Ok(())
    }

    fn stop(&mut self) -> Result<()> {
        // cleanup resources
        Ok(())
    }

    fn poll_logs(&mut self) -> Result<Vec<String>> {
        // return raw log strings since last poll (non-blocking)
        Ok(vec!["2025-01-15 10:30:00 INFO Application started".to_string()])
    }
}

// 2. implement LogParser for your log format
struct MyLogParser;

impl LogParser for MyLogParser {
    fn parse(&self, raw_log: &str) -> Option<LogItem> {
        // parse raw string into LogItem
        // return None to filter out unwanted logs
        Some(LogItem::new(
            raw_log.to_string(),  // parsed content
            raw_log.to_string(),  // original raw string
        ))
    }

    fn format_preview(&self, item: &LogItem, detail_level: u8) -> String {
        // format log for display at given detail level (0-4)
        match detail_level {
            0 => item.content.clone(),
            _ => format!("[{}] {}", item.time, item.content),
        }
    }

    fn get_searchable_text(&self, item: &LogItem, _detail_level: u8) -> String {
        // return text that should be searchable at this detail level
        item.content.clone()
    }
}

// 3. run the application
fn main() -> Result<()> {
    use ratatui::{Terminal, backend::CrosstermBackend};
    use std::io;

    let mut terminal = Terminal::new(CrosstermBackend::new(io::stdout()))?;
    let provider = MyLogProvider { /* ... */ };
    let parser = Arc::new(MyLogParser);

    lazylog_framework::start_with_provider(&mut terminal, provider, parser)?;
    Ok(())
}

§Advanced Configuration

Use AppDesc to customize behavior:

use lazylog_framework::{AppDesc, start_with_desc};
use std::time::Duration;
use std::sync::Arc;

let parser = Arc::new(MyParser);
let mut desc = AppDesc::new(parser.clone());
desc.poll_interval = Duration::from_millis(50);  // poll every 50ms
desc.ring_buffer_size = 32768;  // 32K log capacity
desc.show_debug_logs = true;    // show debug panel

let provider = MyProvider;
start_with_desc(&mut terminal, provider, desc)?;

§Built-in Features

The framework provides a full-featured TUI out of the box:

§Vim-like Navigation

  • j/k, /: move up/down
  • gg: jump to top, G: jump to bottom
  • Ctrl+d/Ctrl+u: page down/up
  • a: toggle autoscroll (like tail -f)

§Filtering

  • /: enter filter mode
  • Type regex pattern to filter logs in real-time
  • Esc: clear filter

§Detail Levels

  • +/-: increase/decrease detail level (0-4)
  • Allows progressive disclosure of information
  • Parser controls what each level shows

§Other Features

  • y: yank (copy) selected log to clipboard
  • w: toggle line wrapping
  • ?: show help popup
  • Mouse support: click and scroll

§Performance

  • Memory-efficient: Ring buffer prevents unbounded growth
  • Lock-free: Uses ringbuf crate for zero-allocation producer/consumer
  • Lazy rendering: Only visible logs are formatted and drawn
  • Parallel filtering: Uses rayon for fast regex filtering on large log sets

§Use Cases

  • File tailing: Monitor local log files in real-time
  • Container logs: Stream from Docker/Kubernetes
  • Network logs: Receive syslog over UDP/TCP
  • Database logs: Query and stream from databases
  • API logs: Fetch from logging services (e.g., Elasticsearch)
  • Device logs: Monitor mobile devices (iOS, Android)
  • Multi-source aggregation: Combine multiple log sources

§Examples

See the examples/ directory for complete implementations:

  • simple.rs: Minimal provider that generates dummy logs
  • file.rs: File-based provider with real-time tailing
  • structured.rs: JSON log parsing with detail levels

Re-exports§

pub use provider::LogDetailLevel;
pub use provider::LogItem;
pub use provider::LogParser;
pub use provider::LogProvider;
pub use provider::decrement_detail_level;
pub use provider::increment_detail_level;
pub use provider::spawn_provider_thread;

Modules§

provider
Provider and parser traits for log acquisition and formatting.

Structs§

AppDesc

Functions§

start_with_desc
Start the application with custom configuration
start_with_provider
Start the application with default configuration