pub struct Queued { /* private fields */ }Expand description
An asynchronous, thread-pooled logger with guaranteed completion.
AsyncLogger acts as an orchestration layer that offloads logging side-effects
to a background pool of workers. It is designed for high-throughput scenarios
where log generation should not block the main application execution.
§Architecture: The “Traveling Sender” Pattern
This logger implements a resilient dispatch system using [crossbeam] channels.
Each Message is wrapped in a PerishableMessage which carries its own
[Sender] clone. This ensures that:
- Decoupled Retries: Workers can re-queue failed tasks without needing access to the parent logger’s state.
- Lifespan Tracking: Messages have a finite number of
lives, preventing infinite loops in case of persistent service failure.
§Graceful Shutdown & Persistence
The AsyncLogger guarantees that no log is lost during program termination:
- Drain Policy: On
drop(), the primary sender is destroyed. Workers will continue processing until the internal buffer is empty and all re-queue attempts (lives) are exhausted. - Thread Synchronization: The logger waits (
join) for all worker threads to finish their tasks before allowing the process to exit.
§Important Design Considerations
- Ordering: Because this logger uses multiple concurrent workers (MPMC),
strict chronological ordering is not guaranteed. While each
Messageretains its original timestamp, the order in which they reach the final destination may vary due to thread scheduling and retry logic. - Compatibility: This pattern is ideal for I/O-bound services like local files or standard streams. It is not recommended for services requiring strict sequential consistency (e.g., Loki or Aws).
§Example
let service = StandardCoutWrite::new();
let logger = QueuedLogger::new(service, 3, 4); // 3 retries, 4 worker threads
let logger = Logger::new(logger);
logger.log((LogLevel::Info,"System started"));Implementations§
Source§impl Queued
impl Queued
Sourcepub fn new(
service: Box<dyn Service + Send + Sync>,
max_retries: usize,
worker_count: usize,
) -> Box<Self>
pub fn new( service: Box<dyn Service + Send + Sync>, max_retries: usize, worker_count: usize, ) -> Box<Self>
Creates a new QueuedLogger and initializes the worker pool.
§Arguments
service- The logging service implementation.max_retries- How many times a failed log should be re-queued.worker_count- The number of background threads to spawn.
Sourcepub fn get_service(&self) -> &dyn Service
pub fn get_service(&self) -> &dyn Service
Returns the base service
Sourcepub fn take_service(self) -> Arc<dyn Service + Send + Sync>
pub fn take_service(self) -> Arc<dyn Service + Send + Sync>
Consumes the logger and returns the underlying service.
This method will block the current thread until all background workers have finished processing the current queue and all retries have been exhausted. This ensures that the returned service is in a clean, idle state.
Trait Implementations§
Source§impl Drop for Queued
impl Drop for Queued
Source§fn drop(&mut self)
fn drop(&mut self)
Orchestrates a graceful shutdown of the logger.
- The primary [
Sender] is dropped (set toNone). - This does not immediately close the channel if messages are in the queue,
as those messages carry their own [
Sender] clones. - Once all messages are processed/exhausted, the last [
Sender] dies. worker_receiver.recv()returnsErr, and threads exit.join()ensures all threads have finished before the program proceeds.
Source§impl LoggerImpl for Queued
impl LoggerImpl for Queued
Auto Trait Implementations§
impl Freeze for Queued
impl !RefUnwindSafe for Queued
impl Send for Queued
impl Sync for Queued
impl Unpin for Queued
impl !UnwindSafe for Queued
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
§impl<T> Instrument for T
impl<T> Instrument for T
§fn instrument(self, span: Span) -> Instrumented<Self>
fn instrument(self, span: Span) -> Instrumented<Self>
§fn in_current_span(self) -> Instrumented<Self>
fn in_current_span(self) -> Instrumented<Self>
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more