log4rc 0.2.0

A log4j-like logging framework for Rust
Documentation
//! Demonstrates the `Appender`/`Layout` extensibility: a custom layout that
//! formats events as `key=value` pairs, and a custom appender that collects
//! formatted messages into a shared in-memory buffer.

use std::sync::{Arc, Mutex};

use log4rc::{Appender, Layout, LogEvent, LogLevel, Logger};

/// A layout that formats events as "key=value" pairs.
struct KeyValueLayout;

impl Layout for KeyValueLayout {
    fn format(&self, event: &LogEvent) -> String {
        format!("level={} message={}", event.level.as_str(), event.message)
    }
}

/// An appender that collects formatted messages into a shared buffer.
#[derive(Clone)]
struct VecAppender {
    layout: Arc<dyn Layout>,
    messages: Arc<Mutex<Vec<String>>>,
}

impl VecAppender {
    fn new(layout: Arc<dyn Layout>) -> Self {
        Self {
            layout,
            messages: Arc::new(Mutex::new(Vec::new())),
        }
    }

    fn messages(&self) -> Vec<String> {
        self.messages.lock().unwrap().clone()
    }
}

impl Appender for VecAppender {
    fn append(&self, event: &LogEvent) {
        self.messages.lock().unwrap().push(self.layout.format(event));
    }
}

fn main() {
    let collector = VecAppender::new(Arc::new(KeyValueLayout));

    // Build a logger with a custom appender and install it as the global logger.
    Logger::builder(LogLevel::Info)
        .appender(Box::new(collector.clone()))
        .init();

    log4rc::info!("Hello, appender!");
    log4rc::debug!("This is filtered out at Info level");
    log4rc::error!("Something went wrong");

    // Only the Info and Error messages made it through the level filter.
    for line in collector.messages() {
        println!("captured: {line}");
    }
}