Thanks to visit codestin.com
Credit goes to lib.rs

#logging #debug-log

rustlog

A small, dependency-light logging crate with a pragmatic API, color (optional), groups, and a scope timer

5 unstable releases

0.3.1 Oct 19, 2025
0.3.0 Oct 19, 2025
0.2.1 Oct 12, 2025
0.2.0 Oct 2, 2025
0.1.0 Sep 25, 2025

#263 in Debugging

Codestin Search App Codestin Search App Codestin Search App Codestin Search App Codestin Search App Codestin Search App Codestin Search App Codestin Search App Codestin Search App Codestin Search App Codestin Search App Codestin Search App

250 downloads per month

MIT/Apache

46KB
910 lines

rustlog

A small, dependency-light logging crate with a pragmatic API, color (optional), groups, and a scope timer.

Features at a glance

  • Macros: trace!, debug!, info!, warn!, error!, fatal!
  • Extras: info_group!(group, ...), scope_time!(label, { ... })
  • Targets: Stdout, Stderr, or a custom writer via set_writer(...) / set_file(path)
  • Runtime toggles: show time, thread id, file:line, group
  • Color (optional): Always / Never / Auto (TTY detection for Stdout/Stderr)
  • Env config: RUST_LOG_LEVEL, RUST_LOG_COLOR, RUST_LOG_SHOW_TID, RUST_LOG_SHOW_TIME
  • Compile-time floor: debug includes trace, release may strip trace/debug

MSRV: Rust 1.70+ (uses OnceLock and std::io::IsTerminal).


Install

[dependencies]
rustlog = "x.x"

Feature flags

  • color — ANSI colors; Auto uses TTY detection for Stdout/Stderr
  • timestamp — prepend timestamp to each line
  • localtime (optional, only if you enable it) — with timestamp, format local time instead of UTC
  • thread-id — include thread id when enabled at runtime

If you don’t enable color, output never contains ANSI escapes.


Quick start

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

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, Writer is treated as non-TTY (no color). Force color with ColorMode::Always if you control the sink.


Levels & filtering

  • Macros: trace!, debug!, info!, warn!, error!, fatal!
  • Compile-time floor:
    • debug builds include trace/debug code paths.
    • release builds may compile out trace/debug; info+ always remains.
  • Runtime filter: set_level(Level::Info) etc.

A record is emitted if:

(level >= compile_time_min) && (level >= runtime_level)

Groups & scope timer

info_group!("db", "query {}", "select 1");
scope_time!("init", { /* code */ }); // logs "took …" at drop

Duration formatting:

  • < 1_000 nsNNN ns
  • < 1_000_000 nsNNN us
  • < 1 sM.us ms (e.g. 1.234 ms)
  • < 60 sS.mmm s (e.g. 1.234 s)
  • < 3600 sMmSS.mmm s (e.g. 2m03.456s)
  • < 24 hHhMMmSS.mmm s (e.g. 1h02m03.456s)
  • 24 hDd HHhMMmSS.mmm s

Colors (feature = color)

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

Timestamps (feature = timestamp)

Enable at runtime:

set_show_time(true);
  • UTC format (default): YYYY-MM-DD HH:MM:SS.mmmZ
  • Local time: enable the localtime 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 (feature = thread-id)

Enable at runtime:

set_show_thread_id(true);

File:line and group tag

set_show_file_line(true); // include `<file:line>`
// group tag is shown when you use info_group!(...) or scope_time!(label, ...)

Application banner (app name & version)

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"
}

Customize name/version explicitly

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.

Environment variables

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

Local Instance

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");

Testing tips

  • To capture output in tests, install a memory writer and select Target::Writer before the first log in that test binary.
  • Targets are set-once. Place target selection at the top of main() or in a per-test binary.
  • Each log line is emitted with a single write_all, guarded by a mutex to avoid interleaving across threads.

License

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.

Dependencies

~205KB