Architecture overview
The async system consists of three main components:- Buffered channel: A queue that holds formatted log entries (worker.go:51)
- Background worker: A goroutine that consumes entries and writes to output (worker.go:50-60)
- Buffered writer: A 64KB buffer that batches writes to reduce syscalls (worker.go:67)
How it works
When you log a message with async enabled:- Velo formats the log entry on your goroutine (zero-copy where possible)
- The formatted buffer is sent to the worker’s channel
- Your goroutine continues immediately without waiting for I/O
- The background worker writes batches of logs to the output stream
The default buffer size is 8192 entries. You can configure this via
Options.BufferSize (options.go:87-88). The buffer size must be a power of 2.Worker lifecycle
Starting a worker
ThenewWorker() function (worker.go:62-80) initializes and starts the background goroutine:
_workers slice (worker.go:33-34) to support flushAllWorkers() for graceful shutdown.
Worker run loop
Therun() method (worker.go:139-168) implements the core processing logic:
Batching optimization
The worker (worker.go:156-163) attempts to drain multiple entries from the queue without blocking, then flushes them together. This reduces the number of syscalls and improves throughput.Buffer management
Velo uses a buffer pool to avoid allocating memory for every log entry. Thesubmit() method (worker.go:100-118) handles buffer submission:
Synchronization
Thesync() method (worker.go:121-129) blocks until all queued logs are written to the underlying writer:
logger.Close() or logger.Sync() before your application exits to ensure all logs are written:
Error handling
The worker tracks write errors vialastErr (worker.go:59) and the handleError() method (worker.go:196-202):
stderr to avoid recursive logging issues. The worker deduplicates identical consecutive errors to prevent spam.
Stopping a worker
Thestop() method (worker.go:86-98) gracefully shuts down the background goroutine:
- Removes the worker from the global registry
- Closes the
stopChanto signal shutdown - Waits for the
flushedchannel to confirm all entries are written
Performance characteristics
- Zero blocking: Your goroutines never wait for I/O under normal conditions
- Batched writes: Multiple log entries are written in a single syscall
- 64KB buffer: Reduces the frequency of writes to the underlying stream
- Buffer pooling: Eliminates allocations for log entry buffers