use nonblocking_logger::{LogLevel, Logger};
use std::io;
use std::path::Path;
use std::thread;
use std::time::Duration;
fn get_test_dir() -> io::Result<String> {
let test_dir = "target/tests";
if !Path::new(test_dir).exists() {
std::fs::create_dir_all(test_dir)?;
}
Ok(test_dir.to_string())
}
fn get_test_file_path(filename: &str) -> io::Result<String> {
let test_dir = get_test_dir()?;
let timestamp = std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.unwrap_or_default()
.as_nanos();
let safe_filename = filename.replace('/', "_").replace('\\', "_");
Ok(format!("{}/test_{}_{}", test_dir, timestamp, safe_filename))
}
fn main() -> Result<(), Box<dyn std::error::Error>> {
println!("=== Direct Logging System Demo ===");
let stdout_logger = Logger::new().stdout();
let stderr_logger = Logger::new().stderr();
let test_file = get_test_file_path("direct_demo.log")?;
let file_logger = Logger::new().file(&test_file)?;
println!("\n1. Basic logging with different targets:");
stdout_logger.info("This goes to stdout")?;
stderr_logger.warning("This goes to stderr")?;
file_logger.info("This goes to file")?;
println!("\n2. Multi-threaded logging demonstration:");
let handles: Vec<_> = (0..5)
.map(|i| {
let logger = Logger::new().stdout();
thread::spawn(move || {
for j in 0..3 {
logger.info(&format!("Thread {} - Message {}", i, j))?;
thread::sleep(Duration::from_millis(10));
}
Ok::<(), Box<dyn std::error::Error + Send + Sync>>(())
})
})
.collect();
for handle in handles {
handle
.join()
.unwrap()
.map_err(|e| format!("Thread error: {:?}", e))?;
}
println!("\n3. Performance test (direct logging):");
let start = std::time::Instant::now();
for i in 0..1000 {
stdout_logger.info(&format!("Performance test message {}", i))?;
}
let direct_time = start.elapsed();
println!(
" Direct logging time for 1000 messages: {:?}",
direct_time
);
println!("\n4. Lazy logging with expensive computation:");
let expensive_logger = Logger::with_level(LogLevel::Info).stdout();
expensive_logger.info_lazy(|| {
println!(" 🔥 Computing expensive result...");
thread::sleep(Duration::from_millis(50));
"Expensive computation completed".to_string()
})?;
expensive_logger.debug_lazy(|| {
println!(" This should not appear!");
"This debug message should not be computed".to_string()
})?;
println!("\n5. Custom formats and time formats:");
let custom_logger = Logger::new()
.time_format("%H:%M:%S%.3f")
.format_for_level(LogLevel::Error, "🚨 ERROR: {message}".to_string())
.format_for_level(LogLevel::Warning, "⚠️ WARN: {message}".to_string())
.format_for_level(LogLevel::Info, "ℹ️ INFO: {message}".to_string())
.stdout();
custom_logger.info("Custom formatted info message")?;
custom_logger.warning("Custom formatted warning message")?;
custom_logger.error("Custom formatted error message")?;
println!("\n6. Demonstrating concurrent logging:");
let concurrent_logger = Logger::new().stdout();
let log_handle = thread::spawn(move || {
for i in 0..10 {
concurrent_logger.info(&format!("Background logging {}", i))?;
thread::sleep(Duration::from_millis(100));
}
Ok::<(), Box<dyn std::error::Error + Send + Sync>>(())
});
println!(" Main thread doing other work...");
for i in 0..5 {
println!(" Main thread work item {}", i);
thread::sleep(Duration::from_millis(50));
}
log_handle
.join()
.unwrap()
.map_err(|e| format!("Logging thread error: {:?}", e))?;
println!("\n7. Final messages demonstration:");
stdout_logger.info("Application is shutting down...")?;
stderr_logger.warning("Final warning message")?;
file_logger.info("Final log entry")?;
thread::sleep(Duration::from_millis(100));
println!("\nLogging complete. Check '{}' for file output.", test_file);
println!("Note: Direct logging provides fast, synchronous output without background threads.");
Ok(())
}