kerf 0.1.2

Simple tokio-based trace event collector
Documentation
use anyhow::Result;
use kerf::{Config, Kerf, Match};
use std::fs::OpenOptions;
use std::io::Write;
use std::sync::{Arc, Mutex};
use tracing::{debug, error, info, warn};

#[tokio::main]
async fn main() -> Result<()> {
    println!("🎯 Kerf Builder Pattern Demo");
    println!("This example demonstrates the new per-tab callback functionality");
    println!("where each tab can have its own dedicated callback function.\n");

    // Create a log file for errors
    let log_file = Arc::new(Mutex::new(
        OpenOptions::new()
            .create(true)
            .write(true)
            .truncate(true)
            .open("/tmp/kerf_errors.log")?,
    ));

    // Create config with multiple tabs - Config remains serializable!
    let config = Config::empty()
        .with_tab("console", Match::info().all_modules())
        .with_tab("errors", Match::error().all_modules())
        .with_tab("debug", Match::debug().module_pattern("demo::*"));

    // Initialize kerf with per-tab callbacks using builder pattern
    let log_file_clone = Arc::clone(&log_file);
    Kerf::init(config)?
        .with_tab_callback("console", |event| {
            // Console tab: print to stdout with nice formatting
            println!("📺 CONSOLE: {}", event.format());
        })
        .with_tab_callback("errors", move |event| {
            // Error tab: write to file AND print to stderr
            eprintln!("❌ ERROR: {}", event.format());

            if let Ok(mut file) = log_file_clone.lock() {
                writeln!(file, "[{}] {}", event.timestamp, event.format_full()).ok();
                file.flush().ok();
            }
        })
        .with_tab_callback("debug", |event| {
            // Debug tab: print with special formatting
            println!(
                "🐛 DEBUG: {} ({}:{})",
                event.message,
                event.file.as_deref().unwrap_or("unknown"),
                event.line.unwrap_or(0)
            );
        })
        .build()
        .await?;

    println!("✅ Kerf initialized with per-tab callbacks!\n");

    // Generate some test events
    info!("Application starting up");
    debug!(target: "demo::startup", "Loading configuration files");
    warn!("This warning won't be captured by any tab");
    error!("Failed to connect to database");
    info!("Retrying database connection");
    debug!(target: "demo::database", "Connection pool initialized");
    error!("Critical system error occurred");

    // Wait for events to be processed
    tokio::time::sleep(tokio::time::Duration::from_millis(500)).await;

    println!("\n🎉 Demo completed!");
    println!("📁 Error log written to: /tmp/kerf_errors.log");

    // Show the error log contents
    let error_log = std::fs::read_to_string("/tmp/kerf_errors.log")?;
    if !error_log.is_empty() {
        println!("\n📋 Error log contents:");
        println!("{error_log}");
    }

    println!("\n💡 Key benefits of the builder pattern:");
    println!("   • Each tab has its own dedicated callback");
    println!("   • No more complex routing logic in a single callback");
    println!("   • Config remains fully serializable");
    println!("   • Clean separation of concerns");
    println!("   • Easy to compose and reuse tab configurations");

    Ok(())
}