7 unstable releases

0.3.2 Feb 6, 2023
0.3.1 Aug 10, 2022
0.2.0 Mar 19, 2022
0.1.0 Mar 13, 2022
0.0.7 Mar 13, 2022

#135 in Debugging

Download history 153/week @ 2023-11-19 129/week @ 2023-11-26 107/week @ 2023-12-03 129/week @ 2023-12-10 138/week @ 2023-12-17 25/week @ 2023-12-24 150/week @ 2023-12-31 314/week @ 2024-01-07 247/week @ 2024-01-14 196/week @ 2024-01-21 184/week @ 2024-01-28 87/week @ 2024-02-04 126/week @ 2024-02-11 293/week @ 2024-02-18 285/week @ 2024-02-25 200/week @ 2024-03-03

911 downloads per month
Used in 8 crates

MIT license

35KB
259 lines

sensible-env-logger

github crates.io docs.rs build status

A pretty, sensible logger for Rust - ideal for running examples and tests on a crate of choice.

This is a thin wrapper around pretty_env_logger. It requires minimal configuration to set up, and writes to standard error with nice colored output for log levels.

example-output


This crate works with Cargo with a Cargo.toml like:

[dependencies]
log = "0.4"
sensible-env-logger = "0.3"

Getting started

The sensible-env-logger is ideally used when writing out examples or tests for a Cargo project or crate. It can be added as a dev-dependency if needed.

First, add some usage to your application:

#[macro_use] extern crate log;

fn main() {
    sensible_env_logger::init!();

    info!("such information");
    warn!("o_O");
    error!("much error");
}

Then run your app with cargo, and you should see the full log output:

cargo run

Alternatively, run your app with the environment variables that control the log level for external crates as well as your crate explicitly set:

GLOBAL_RUST_LOG=warn RUST_LOG=trace cargo run

Even though this crate has the name env in it, using the sensible-env-logger in code is dead simple, and requires minimal configuration.

Examples

You can check out sample usage of this crate in the examples/ folder in the project repo on GitHub.

Defaults

The helper macros below can be used to configure the global logger with sensible defaults. Their sample log output is also shown.

Note: any helper macros, such as init!(), should be called early in the execution of a Rust program.

init!()

Initializes the global logger with a pretty, sensible env logger.

INFO  my_module         > an informational message

init_timed!()

Initializes the global logger with a timed pretty, sensible env logger.

2022-03-24T17:15:31.683Z INFO  my_module         > an informational message

init_timed_short!() - *

Initializes the global logger with a localized time pretty, sensible env logger.

12:15:31.683 INFO  my_module         > an informational message

init_timed_local!() - *

Initializes the global logger with a "no-frills" local date/time pretty, sensible env logger.

2022-03-24 12:15:31.683 - INFO  my_module         > an informational message

init_timed_local_iso!() - *

Initializes the global logger with a local-timed pretty, sensible env logger.

This variant formats log messages with a localized timestamp, in ISO-8601/ RFC 3339 date & time format.

2022-03-24T12:15:31.683+08:00 INFO  my_module         > an informational message

Optional Features

Local Time

Using the macros marked with a * above, require the local-time feature to be enabled:

[dev-dependencies]
sensible-env-logger = { version = "0.3", features = ["local-time"] }

In Tests

When running tests on a crate, you can use the safe_init!() macro as shown below. This should ignore errors when initializing the global logger multiple times.

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_one() {
        sensible_env_logger::safe_init!();
        trace!("hello from the first test")
    }

    #[test]
    fn test_two() {
        sensible_env_logger::safe_init!();
        trace!("hello from the second test")
    }
}

Rationale

Imagine you are testing out a Cargo project named my_rust_project. That is, the Cargo.toml in your project would look something like this:

[package]
name = "my-rust-project"

[dependencies]
log = "*"

Assuming you are building a library, your src/lib.rs could look like this:

#[macro_use] extern crate log;

pub fn my_awesome_fn() {
    trace!("getting ready to do something cool...");
    std::thread::sleep(std::time::Duration::from_millis(500));
    info!("finished!");
}

You then create a new example file named examples/my_example.rs, with the following contents:

use my_rust_project::my_awesome_fn;
#[macro_use] extern crate log;

fn main() {
    debug!("my debug message");
    my_awesome_fn();
    error!("oops! something went wrong!");
}

You can run the new file with cargo run --example my_example. The problem here is that you won't get any terminal output by default; this is because you need to set up the RUST_LOG environment variable beforehand, in order to see the expected log output.

Setting the RUST_LOG variable works, but there are a few issues with this. For example, what if your Cargo project uses other external libraries? Ideally you want to see the trace logs from your own project (the crate under test), but not the trace logs from these other libraries. In that case, setting RUST_LOG=trace doesn't seem the best approach here.

You could then set the RUST_LOG environment variable to the following log format:

$ export RUST_LOG='warning,my_rust_project=trace,my_example=trace'

When leveraging the pretty_env_logger crate and adding a pretty_env_logger::init() at the top of the main function, this does now work as expected and produce the desired log output.

However, there are few limitations with this approach:

  • In your Cargo project, you'd need to update the documentation for running examples to mention that you need to export the RUST_LOG env variable explicitly. For instance, you'd need to mention that an example is ideally run like RUST_LOG=trace cargo run --example my_example.

  • You'd need to remember to set the RUST_LOG env variable each time. This can be troublesome when your Windows machine reboots for example, or whenever you open a new terminal window.

To solve these minor issues you can simply use the sensible_env_logger crate, which automatically sets up sensible defaults; this involves generating and using a directive string in the same form as the $RUST_LOG environment variable.

Now, the updated code in the examples/my_example.rs would look like this:

use my_rust_project::my_awesome_fn;
#[macro_use] extern crate log;

fn main() {
    sensible_env_logger::init!();

    debug!("my debug message");
    my_awesome_fn();
    error!("oops! something went wrong!");
}

Contributing

Contributions are welcome! Open a pull request to fix a bug, or open an issue to discuss a new feature or change.

Check out the Contributing section in the docs for more info.

License

This project is proudly licensed under the MIT license (LICENSE or http://opensource.org/licenses/MIT).

sensible-env-logger can be distributed according to the MIT license. Contributions will be accepted under the same license.

Authors

Dependencies

~2–10MB
~72K SLoC