| Crates.io | inqjet |
| lib.rs | inqjet |
| version | 0.2.0 |
| created_at | 2025-07-28 03:46:25.27071+00 |
| updated_at | 2025-10-01 17:45:31.718593+00 |
| description | Ultra-fast, low-latency logging for Rust applications |
| homepage | https://github.com/Abso1ut3Zer0/inqjet |
| repository | https://github.com/Abso1ut3Zer0/inqjet |
| max_upload_size | |
| id | 1770635 |
| size | 91,860 |
Ultra-fast, low-latency logging for Rust applications
InqJet is a high-performance logging library designed for latency-critical applications where every microsecond counts. It achieves consistent single-digit Ξs producer-side overhead by decoupling log formatting from I/O operations using a lock-free architecture.
Initialize the logger:
use inqjet::InqJetBuilder;
use log::{info, error, LevelFilter};
fn main() -> Result<(), Box<dyn std::error::Error>> {
// Initialize logger with stdout output
let _guard = InqJetBuilder::default()
.with_writer(std::io::stdout())
.with_log_level(LevelFilter::Info)
.build()?;
// Use standard logging macros
info!("Server started on port {}", 8080);
error!("Connection failed: timeout");
// Logger automatically shuts down when guard is dropped
Ok(())
}
InqJet is specifically optimized for producer-side latency - the time it takes for a log statement to be passed to the background appender thread.
[Producer Threads] â [Logger] â [Lock-free Channel] â [Background Thread] â [Output]
â â â â â
log!() calls Format msg Queue message Write to I/O File/Stdout
(1-5Ξs) Pool strings (lock-free) (background)
crossbeam::ArrayQueue for zero-contention message passingInqJet produces structured, colored log output:
2024-01-15T14:30:45.123456Z [INFO] my_app::auth:127 - User alice logged in
2024-01-15T14:30:45.124001Z [ERROR] my_app::db - Connection failed: timeout
ââ Timestamp (gray) ââ Level (colored) ââ Target:line (gray) ââ Message
ââ ISO 8601 with Ξs ââ Color coded ââ Optional line number ââ User content
let _guard = InqJetBuilder::default()
.with_writer(std::io::stdout())
.with_log_level(LevelFilter::Info)
.build()?;
use std::fs::OpenOptions;
let file = OpenOptions::new()
.create(true)
.append(true)
.open("app.log")?;
let _guard = InqJetBuilder::default()
.with_writer(file)
.with_log_level(LevelFilter::Debug)
.build()?;
Configure the string capacity in the string pool based on your typical log message length.
let _guard = InqJetBuilder::default()
.with_string_capacity(1024) // 1KB sized strings in pool
.build()?;
Size the channel based on your burst patterns:
let _guard = InqJetBuilder::default()
.with_capacity(4096) // Large buffer for traffic bursts
.build()?;
For absolute minimum latency (lowest possible tails), use spinning appender (dedicates a CPU core):
let _guard = InqJetBuilder::default()
.with_timeout(None) // Spin forever, never park
.build()?;
Performance impact:
unpark() - no kernel overhead for wakeupsFor responsive shutdown with minimal overhead:
use std::time::Duration;
let _guard = InqJetBuilder::default()
.with_timeout(Some(Duration::from_millis(5))) // Default
.build()?;
InqJet works with any Write + Send + 'static type:
use std::net::TcpStream;
// Network logging
let stream = TcpStream::connect("log-server:514")?;
let _guard = InqJetBuilder::default()
.with_writer(stream)
.build()?;
// Multiple outputs (using a custom writer)
struct MultiWriter {
stdout: std::io::Stdout,
file: std::fs::File,
}
impl std::io::Write for MultiWriter {
fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
self.stdout.write_all(buf)?;
self.file.write_all(buf)?;
Ok(buf.len())
}
fn flush(&mut self) -> std::io::Result<()> {
self.stdout.flush()?;
self.file.flush()
}
}
InqJet is fully compatible with the standard log crate:
// Works with any crate using the log facade
use log::{info, debug, error};
use serde_json::json;
// Structured logging
let user_data = json!({
"user_id": 12345,
"action": "login",
"ip": "192.168.1.100"
});
info!("User event: {}", user_data);
// Error logging with context
if let Err(e) = risky_operation() {
error!("Operation failed: {} (retrying in 5s)", e);
}
env_logger is simplertracingCurrently InqJet has no optional features - it's designed to be minimal and fast by default.
tracing?A: tracing is excellent for structured logging and observability, but has higher latency overhead (10-50Ξs cold start vs 1-5Ξs for InqJet). If you need structured data and spans, use tracing. If you need raw speed, use InqJet.
A: Yes! InqJet works perfectly with tokio, async-std, and other runtimes. The background thread is independent of your async runtime.
A: Not directly. Use external tools like logrotate or provide a custom writer that handles rotation.
A: Producers will block with exponential backoff until the consumer catches up. No messages are dropped - InqJet guarantees delivery.
A: No, InqJet sets itself as the global logger. Only one logger can be active per process.