llt-rs 0.6.0

Low-Latency Primitives Toolkit for Rust
Documentation
# Non-Blocking Logger

A high-performance logging facility designed for low-latency applications.

## Overview

Standard logging (like println! or log crate implementations writing to files) involves Blocking I/O.
If your hot-path thread (e.g., a Real-time Audio Processor, Game Loop, or Event Handler) calls a logger that blocks waiting for a disk write or a mutex on stdout, you introduce massive, non-deterministic latency spikes.

This module solves this by offloading the I/O to a dedicated thread.


## Architecture

**The SPSC Channel**: We use llt-rs::channel to pass log messages from the hot thread to the logger thread.

**Zero-Blocking Guarantee**: The logger uses try_send. If the logging buffer is full, the message is dropped (and a counter incremented) rather than blocking the main execution thread. In low-latency systems, it is better to lose a log line than to violate timing constraints or stall the critical path.

**Pinned Worker**: The background logging thread can be optionally pinned to a specific CPU core (using llt-rs::affinity) to keep it away from your critical processing cores.

## Setup

```
[dependencies]
llt-rs = { version = "0.6.0", features = ["logger"] }

```
## Usage

This example simulates a generic High-Frequency Event Loop. Notice how the hot path logs complex events without ever blocking on I/O.


```
use llt_rs::logger::Logger;
use std::thread;
use std::time::Duration;

fn main() {
    // 1. Initialize the logger with a large buffer (power of 2).
    // This spawns the background writer thread immediately.
    let logger = Logger::new(4096);

    println!("System starting...");

    // 2. Simulate a Hot Path (e.g., Sensor Data Ingest or Audio Callback)
    // We clone the logger to pass it to the new thread.
    let log_handle = logger.clone();
    
    let handle = thread::spawn(move || {
        // Simulating a burst of high-frequency events
        for i in 0..100 {
            // CRITICAL: This call takes nanoseconds.
            // It creates the string and pushes pointers.
            // It does NOT wait for stdout/disk.
            log_handle.log(format!("[SENSOR] Event ID: {} | Value: {:.4}", i, i as f64 * 1.5));
            
            // Simulate work (processing the event)
            // In reality, this sleep would be absent or microsecond-scale.
            thread::sleep(Duration::from_micros(10));
        }
        log_handle.log("[SYSTEM] Batch processing complete.");
    });

    // 3. The main thread can do other work...
    thread::sleep(Duration::from_millis(50));
    println!("Main thread working...");

    handle.join().unwrap();
    
    // 4. Check metrics before exit
    let dropped = logger.get_dropped_count();
    if dropped > 0 {
        eprintln!("Warning: Logger dropped {} messages due to backpressure.", dropped);
    }
    
    // Give the background thread a tiny slice of time to flush the remaining buffer
    thread::sleep(Duration::from_millis(10));
}

```