Skip to main content

NonBlocking

Struct NonBlocking 

Source
pub struct NonBlocking<F: Format> { /* private fields */ }
Available on crate feature std only.
Expand description

A sink that formats on the calling thread and writes on a background thread.

Records are formatted into a String, queued on a bounded channel, and written by a dedicated thread through an internal write buffer. The worker flushes whenever the queue drains, so records reach the OS promptly once logging pauses, and in large batches under load. This keeps file and socket I/O off request threads and async executor threads.

  • Bounded: at most capacity records, and about max_queued_bytes bytes of formatted text (16 MiB by default), are queued. What happens when either limit is reached is set by Overflow; the default, Overflow::Block, never drops a record.
  • Flush: Sink::flush waits until every record queued before it has been written and the writer flushed.
  • Shutdown: Sink::shutdown (called by crate::Logger::shutdown, a crate::FlushGuard, or dropping the last logger clone) drains the queue, flushes, and joins the thread. Records logged afterwards are written synchronously on the caller’s thread, so late records are not lost.
  • Errors: a write error on the worker cannot be returned to the caller that logged the record. It is counted (NonBlocking::write_errors), passed to the optional NonBlockingBuilder::on_error handler, and returned by the next flush.
  • Allocation: queued strings are recycled through a return channel, so a single producer allocates only while the pool warms up, which can take up to capacity records when the producer outruns the writer; with heavy multi-thread contention some records allocate. The pool keeps at most capacity buffers of up to 64 KiB each.

As with any buffering sink, records still queued when the process aborts are lost; see super::FileSink for the exit paths that skip destructors.

The writer and the worker’s on_error handler may log through a logger that feeds this same sink, but the worker never waits for itself: on the worker thread, a record that does not fit in the queue is dropped and counted (even under Overflow::Block), a flush-level flush is skipped (the worker flushes once it drains the queue), and Sink::flush and Sink::shutdown return Error::Closed at once. Records written that way are delayed behind the current batch, and they feed the writer again, so keep such logging rare.

§Examples

use log_io::format::JsonFormat;
use log_io::sink::{NonBlocking, Overflow};
use log_io::{Level, Logger};

let sink = NonBlocking::builder(std::io::sink(), JsonFormat::new())
    .capacity(4096)
    .overflow(Overflow::DropNewest)
    .build()?;
let logger = Logger::builder().level(Level::Info).with_sink(sink).build();
log_io::info!(logger, "off the hot path", worker = 3_u32);
logger.shutdown()?; // drain and join

Implementations§

Source§

impl<F: Format> NonBlocking<F>

Source

pub fn new<W: Write + Send + 'static>(writer: W, format: F) -> Result<Self>

Start a background writer with default options: capacity 8192, 16 MiB of queued text, Overflow::Block.

§Errors

Returns Error::Io if the worker thread cannot be spawned.

Source

pub fn builder<W: Write + Send + 'static>( writer: W, format: F, ) -> NonBlockingBuilder<F>

Start configuring a background writer.

Source

pub fn dropped(&self) -> u64

Records dropped because the queue was full under Overflow::DropNewest.

Source

pub fn write_errors(&self) -> u64

Write errors encountered by the background thread.

Source

pub fn queued_bytes(&self) -> usize

Bytes of formatted text queued and not yet written.

Trait Implementations§

Source§

impl<F: Format + Debug> Debug for NonBlocking<F>

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl<F: Format> Drop for NonBlocking<F>

Source§

fn drop(&mut self)

Executes the destructor for this type. Read more
Source§

fn pin_drop(self: Pin<&mut Self>)

🔬This is a nightly-only experimental API. (pin_ergonomics)
Execute the destructor for this type, but different to Drop::drop, it requires self to be pinned. Read more
Source§

impl<F: Format> Sink for NonBlocking<F>

Source§

fn write_record(&self, record: &Record<'_>) -> Result<()>

Serialize and deliver one record. Read more
Source§

fn flush(&self) -> Result<()>

Push any buffered bytes to the destination (for files, to the operating system; see the sink’s own docs for fsync). Read more
Source§

fn request_flush(&self) -> Result<()>

Flush triggered by a record at or above the logger’s flush level (see crate::LoggerBuilder::flush_on). Read more
Source§

fn shutdown(&self) -> Result<()>

Flush and release background resources. Called by crate::Logger::shutdown, by a crate::FlushGuard on drop, and when the last clone of a crate::Logger is dropped. Read more

Auto Trait Implementations§

§

impl<F> !Freeze for NonBlocking<F>

§

impl<F> !RefUnwindSafe for NonBlocking<F>

§

impl<F> !UnwindSafe for NonBlocking<F>

§

impl<F> Forget for NonBlocking<F>

§

impl<F> Move for NonBlocking<F>

§

impl<F> Send for NonBlocking<F>

§

impl<F> Sync for NonBlocking<F>

§

impl<F> Unpin for NonBlocking<F>
where F: Unpin,

§

impl<F> UnsafeUnpin for NonBlocking<F>
where F: UnsafeUnpin,

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = !

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, !>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.