nonblocking-logger 0.3.0

A high-performance library with format string support
Documentation
use nonblocking_logger::Logger;
use std::io;
use std::io::Write;
use std::path::Path;
use futures::io::AsyncWrite;

/// Get the test directory path for temporary files
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())
}


/// Get a test file path in the test directory
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!("=== AsyncWrite to Write Conversion Example ===");

    println!("\n=== Example 1: Custom AsyncWrite implementation ===");
    let custom_writer = CustomAsyncWriter::new();
    let mut sync_writer = AsyncToSyncWriter::new(custom_writer);

    println!("Testing custom AsyncWrite implementation:");
    sync_writer.write_all(b"Custom async writer message\n")?;
    sync_writer.flush()?;

    println!("\n=== Example 2: AsyncToSyncWriter with Vec<u8> ===");
    let vec_writer = Vec::<u8>::new();
    let mut vec_sync_writer = AsyncToSyncWriter::new(vec_writer);

    println!("Testing AsyncToSyncWriter with Vec<u8>:");
    vec_sync_writer.write_all(b"Message written to Vec<u8>\n")?;
    vec_sync_writer.flush()?;

    println!("\n=== Example 3: Using converted AsyncWrite with Logger ===");
    let async_writer = Vec::<u8>::new();
    let sync_writer = AsyncToSyncWriter::new(async_writer);
    let logger = Logger::new().add_target(sync_writer);

    println!("Testing converted AsyncWrite with Logger:");
    logger.info("This message goes through converted AsyncWrite!")?;
    logger.warning("Warning via converted AsyncWrite")?;
    logger.error("Error via converted AsyncWrite")?;

    println!("\n=== Example 4: Regular Logger with file (for comparison) ===");
    let test_file = get_test_file_path("async_example.log")?;
    let logger = Logger::new().file(&test_file)?.no_time_prefix();

    logger.info("This uses regular Logger with file")?;
    logger.warning("Warning via regular Logger file")?;
    logger.error("Error via regular Logger file")?;

    std::thread::sleep(std::time::Duration::from_millis(100));

    std::fs::remove_file(&test_file).ok();

    println!("\n=== AsyncWrite to Write Conversion Summary ===");
    println!("AsyncToSyncWriter allows you to:");
    println!("- Convert any AsyncWrite + Unpin to a sync Write trait");
    println!("- Bridge async and sync I/O seamlessly using futures::block_on");
    println!("- Create custom AsyncWrite implementations");
    println!("- Use async streams with synchronous logging infrastructure");
    println!("- Handle network errors gracefully");

    Ok(())
}

/// Simple adapter to convert AsyncWrite to Write
struct AsyncToSyncWriter<W: AsyncWrite + Unpin> {
    writer: W,
}

impl<W: AsyncWrite + Unpin> AsyncToSyncWriter<W> {
    fn new(writer: W) -> Self {
        Self { writer }
    }
}

impl<W: AsyncWrite + Unpin> Write for AsyncToSyncWriter<W> {
    fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
        futures::executor::block_on(async {
            use futures::io::AsyncWriteExt;
            self.writer.write_all(buf).await?;
            Ok(buf.len())
        })
    }

    fn flush(&mut self) -> std::io::Result<()> {
        futures::executor::block_on(async {
            use futures::io::AsyncWriteExt;
            self.writer.flush().await
        })
    }
}

/// A custom AsyncWrite implementation for demonstration
struct CustomAsyncWriter {
    buffer: Vec<u8>,
}


impl CustomAsyncWriter {
    fn new() -> Self {
        Self { buffer: Vec::new() }
    }
}


impl futures::io::AsyncWrite for CustomAsyncWriter {
    fn poll_write(
        mut self: std::pin::Pin<&mut Self>,
        _cx: &mut std::task::Context<'_>,
        buf: &[u8],
    ) -> std::task::Poll<std::io::Result<usize>> {
        self.buffer.extend_from_slice(buf);

        if let Ok(text) = std::str::from_utf8(buf) {
            print!("[CUSTOM ASYNC WRITER] {}", text);
        }

        std::task::Poll::Ready(Ok(buf.len()))
    }

    fn poll_flush(
        self: std::pin::Pin<&mut Self>,
        _cx: &mut std::task::Context<'_>,
    ) -> std::task::Poll<std::io::Result<()>> {
        std::task::Poll::Ready(Ok(()))
    }

    fn poll_close(
        self: std::pin::Pin<&mut Self>,
        _cx: &mut std::task::Context<'_>,
    ) -> std::task::Poll<std::io::Result<()>> {
        std::task::Poll::Ready(Ok(()))
    }
}