An open API service indexing awesome lists of open source software.

https://github.com/rnag/sensible-env-logger

A pretty, sensible, easy-to-use logger for Rust.
https://github.com/rnag/sensible-env-logger

Last synced: 9 months ago
JSON representation

A pretty, sensible, easy-to-use logger for Rust.

Awesome Lists containing this project

README

          

# sensible-env-logger

[github](https://github.com/rnag/sensible-env-logger)
[crates.io](https://crates.io/crates/sensible-env-logger)
[docs.rs](https://docs.rs/sensible-env-logger)
[build status](https://github.com/rnag/sensible-env-logger/actions?query=branch%3Amain)

> 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](readme-example.png)

[pretty_env_logger]: https://docs.rs/pretty_env_logger

---

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

```toml
[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.

[examples]: http://xion.io/post/code/rust-examples.html
[tests]: https://doc.rust-lang.org/book/ch11-01-writing-tests.html
[`dev-dependency`]: https://doc.rust-lang.org/rust-by-example/testing/dev_dependencies.html

First, add some usage to your application:

```rust
#[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:

```console
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:

```console
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/](https://github.com/rnag/sensible-env-logger/tree/main/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.

```console
INFO my_module > an informational message
```

### `init_timed!()`

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

```console
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.

```console
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.

```console
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.

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

## Optional Features

[`*`]: #local-time

### Local Time

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

```toml
[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.

```rust
#[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:

```toml,no_sync
[package]
name = "my-rust-project"

[dependencies]
log = "*"
```

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

```rust
#[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:

```rust
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!");
}
```

[example]: http://xion.io/post/code/rust-examples.html

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]:

```shell
$ 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:

```rust
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!");
}
```

[log format]: https://rust-lang-nursery.github.io/rust-cookbook/development_tools/debugging/config_log.html

## 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.

[Contributing]: CONTRIBUTING.md
[open an issue]: https://github.com/rnag/sensible-env-logger/issues

## License

This project is proudly licensed under the MIT license ([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

* [Ritvik Nag](https://github.com/rnag)