| Crates.io | rustlog |
| lib.rs | rustlog |
| version | 0.3.1 |
| created_at | 2025-09-25 19:43:36.705442+00 |
| updated_at | 2025-10-19 18:20:12.995039+00 |
| description | A small, dependency-light logging crate with a pragmatic API, color (optional), groups, and a scope timer |
| homepage | https://github.com/milchinskiy/rustlog |
| repository | https://github.com/milchinskiy/rustlog |
| max_upload_size | |
| id | 1855037 |
| size | 103,830 |
A small, dependency-light logging crate with a pragmatic API, color (optional), groups, and a scope timer.
trace!, debug!, info!, warn!, error!, fatal!info_group!(group, ...), scope_time!(label, { ... })Stdout, Stderr, or a custom writer via set_writer(...) / set_file(path)Always / Never / Auto (TTY detection for Stdout/Stderr)RUST_LOG_LEVEL, RUST_LOG_COLOR, RUST_LOG_SHOW_TID, RUST_LOG_SHOW_TIMEdebug includes trace, release may strip trace/debugMSRV: Rust 1.70+ (uses
OnceLockandstd::io::IsTerminal).
[dependencies]
rustlog = "x.x"
color — ANSI colors; Auto uses TTY detection for Stdout/Stderrtimestamp — prepend timestamp to each linelocaltime (optional, only if you enable it) — with timestamp, format local time instead of UTCthread-id — include thread id when enabled at runtimeIf you don’t enable
color, output never contains ANSI escapes.
use rustlog::*;
fn main() {
// Choose output early; first call wins (set-once semantics).
set_target(Target::Stderr); // default if unset
// set_file("/var/log/app.log").unwrap(); // or write to a file
// Configure runtime toggles
set_show_time(true); // requires `timestamp` feature
set_show_thread_id(false); // requires `thread-id` feature
set_show_file_line(true);
// Runtime level (compile-time floor still applies)
set_level(Level::Info);
info!("hello {}", 42);
warn!("heads up");
info_group!("net", "retry #{}", 3);
scope_time!("startup", {
// work …
}); // logs "took …" when the scope ends
}
Typical output (UTC timestamp shown when timestamp is enabled; colors elided):
2025-09-25 12:34:56.789Z INFO <main.rs:15> hello 42
2025-09-25 12:34:56.790Z WARN <main.rs:16> heads up
2025-09-25 12:34:56.791Z INFO <main.rs:19> [net] retry #3
2025-09-25 12:34:56.792Z INFO <main.rs:22> [startup] took 1.234 ms
Targets are set once for the process (internally OnceLock). Set them at program start.
set_target(Target::Stdout);
set_target(Target::Stderr); // default
set_file("app.log").unwrap(); // convenience: opens/creates + selects `Writer`
// Custom sink (useful in tests):
use std::io::Write;
struct Mem(Vec<u8>);
impl Write for Mem {
fn write(&mut self, b: &[u8]) -> std::io::Result<usize> { self.0.extend_from_slice(b); Ok(b.len()) }
fn flush(&mut self) -> std::io::Result<()> { Ok(()) }
}
set_writer(Box::new(Mem(Vec::new())));
set_target(Target::Writer);
With
ColorMode::Auto,Writeris treated as non-TTY (no color). Force color withColorMode::Alwaysif you control the sink.
trace!, debug!, info!, warn!, error!, fatal!debug builds include trace/debug code paths.release builds may compile out trace/debug; info+ always remains.set_level(Level::Info) etc.A record is emitted if:
(level >= compile_time_min) && (level >= runtime_level)
info_group!("db", "query {}", "select 1");
scope_time!("init", { /* code */ }); // logs "took …" at drop
Duration formatting:
< 1_000 ns → NNN ns< 1_000_000 ns → NNN us< 1 s → M.us ms (e.g. 1.234 ms)< 60 s → S.mmm s (e.g. 1.234 s)< 3600 s → MmSS.mmm s (e.g. 2m03.456s)< 24 h → HhMMmSS.mmm s (e.g. 1h02m03.456s)≥ 24 h → Dd HHhMMmSS.mmm scolor)set_color_mode(ColorMode::Always); // force ANSI
set_color_mode(ColorMode::Never); // disable
set_color_mode(ColorMode::Auto); // Stdout/Stderr use TTY detect; Writer = no color
Env override (read by init_from_env()):
RUST_LOG_COLOR=always|never|auto
timestamp)Enable at runtime:
set_show_time(true);
YYYY-MM-DD HH:MM:SS.mmmZlocaltime feature (if you turn it on in your build) to use the system local time.The UTC path uses a correct Gregorian conversion with no external deps.
thread-id)Enable at runtime:
set_show_thread_id(true);
set_show_file_line(true); // include `<file:line>`
// group tag is shown when you use info_group!(...) or scope_time!(label, ...)
Use the banner!() macro to print your app’s name and version as a single info-level line.
use rustlog::*;
fn main() {
set_target(Target::Stderr);
set_level(Level::Info);
banner!(); // -> "myapp v1.2.3"
}
If you don’t want to use Cargo metadata, pass strings directly:
banner!("myapp", "1.2.3");
banner!() is allocation-free and safe to call early during startup.
Call init_from_env() once at startup to read these:
| Variable | Values | Effect |
|---|---|---|
RUST_LOG_LEVEL |
trace debug info warn error fatal |
Sets runtime level |
RUST_LOG_COLOR |
always never auto |
Sets color mode |
RUST_LOG_SHOW_TID |
1 true (case-insensitive) |
Show thread id |
RUST_LOG_SHOW_TIME |
1 true (case-insensitive) |
Show timestamp |
Example:
RUST_LOG_LEVEL=debug RUST_LOG_COLOR=auto RUST_LOG_SHOW_TIME=1 cargo run
Enable multiple logger instances with independent settings while keeping the root API (rustlog::info!, etc.) simple and unchanged for default usage.
rustlog::set_level(Level::Info);
rustlog::info!("default path");
// local instance
use rustlog::local::{Logger, LoggerBuilder};
use rustlog::local::info as linfo;
let lg = Logger::builder().file("trace.log").set_level(Level::Trace).build_static()?;
linfo!(&lg, "per-instance output");
Target::Writer before the first log in that test binary.main() or in a per-test binary.write_all, guarded by a mutex to avoid interleaving across threads.Dual-licensed under MIT or Apache-2.0 at your option.
SPDX-License-Identifier: MIT OR Apache-2.0
If you contribute, you agree to license your contributions under the same terms.