log_nonblock

Crates.iolog_nonblock
lib.rslog_nonblock
version0.1.6
created_at2025-11-17 15:14:33.993096+00
updated_at2025-11-18 17:47:30.243193+00
descriptionAsyncronus logger that prints all messages to STDOUT or STDERR in non blocking mode
homepage
repositoryhttps://github.com/ovr/log_nonblock
max_upload_size
id1936973
size74,189
Dmitry Patsura (ovr)

documentation

README

log-nonblock

Crates.io Documentation

A high-performance Rust logging library that implements truly non-blocking writes to STDOUT/STDERR.

Motivation

Problem #1: STDOUT/STDERR Writes Are Synchronous Blocking Operations

Click to expand explanation

Writing to STDOUT or STDERR is a slow I/O operation, and by default in Rust (and most languages), these are synchronous blocking calls:

println!("Log message");  // Your thread STOPS here until the write completes
log::info!("Log message"); // Same - blocks until written

When you write to STDOUT/STDERR, your application thread stops and waits until the operating system completes the write operation. This might seem fast on your terminal, but it becomes a critical bottleneck when:

  • STDOUT is piped to a slow consumer: Files on slow disks, network streams, terminals that can't keep up
  • Large log messages: Writing megabytes of data can take hundreds of milliseconds
  • High-frequency logging: Each log call blocks your thread, multiplying the cost
  • Performance-critical applications: Web servers, real-time systems, high-throughput data processing

The impact: Each log operation can take 1-10ms or more, during which your application is doing nothing but waiting for I/O to complete.

Problem #2: Rust's Standard Library Doesn't Support Non-Blocking STDOUT

Real-world example: When building Rust modules that run inside Node.js (using N-API, neon, or similar), Node.js sets STDOUT/STDERR to non-blocking mode by default. This causes standard Rust logging crates to panic with "Resource temporarily unavailable" errors, making them unusable in Node.js environments without special handling.

Click to expand explanation

You might think: "I'll just set STDOUT to non-blocking mode at the OS level!" Unfortunately, this doesn't work with Rust's standard library:

// Set STDOUT to non-blocking mode (using fcntl)
set_nonblocking(stdout);

// This will PANIC when the buffer is full!
println!("Large message");  // L thread panicked: failed printing to stdout: Resource temporarily unavailable

The problem: When STDOUT/STDERR is in non-blocking mode, the OS returns WouldBlock errors when the output buffer is full. Rust's std::io::Stdout and the println!/eprintln! macros are not designed to handle this - they will panic immediately.

This happens with:

  • Rust modules running in Node.js: Node.js uses non-blocking I/O by default, causing panics in standard Rust crates
  • Large messages that don't fit in the kernel buffer (~64KB on most systems)
  • Parallel usage from multiple threads overwhelming the output buffer
  • Any situation where the consumer can't keep up with your write rate

You cannot simply use non-blocking I/O with Rust's standard library - you need proper handling of WouldBlock errors.

Problem #3: The Performance Impact

Click to expand explanation

In a typical web application logging at INFO level:

// Each request logs ~5-10 times
log::info!("Request received: {}", request);
// ... blocked for 1-5ms ...
log::debug!("Processing: {}", data);
// ... blocked for 1-5ms ...
log::info!("Response sent: {}", response);
// ... blocked for 1-5ms ...

Result: N ms of your request latency is spent waiting for I/O operations. In a system handling 1000 req/s, this can be the difference between meeting your SLA and missing it.

Benchmarks

See BENCH_RESULTS for detailed results, metrics, and instructions.

License

MIT

Formating and options part are based on rust-simple_logger, which is authored by Sam Clements under MIT license

Commit count: 0

cargo fmt