Open-source project
rust-cli/env_logger avatar
rust-cli/env_logger

env_logger: the Rust logger whose verbosity comes from RUST_LOG

A logging implementation for `log` which is configured via an environment variable.

1,064 stars150 forksRustApache-2.0

At a glance

What is it?
env_logger is the Apache-2.0 or MIT licensed logger that implements the log facade for Rust binaries and reads its level filter from an environment variable, so the same binary can log nothing in production and everything on a laptop. It suits a small crate or a CLI that wants zero configuration, and it is the wrong choice for a library or for anything that needs a stable machine-readable log format.
Who is it for?
env_logger fits a Rust binary or command line tool that needs logging with no configuration file and no code changes, because the RUST_LOG variable controls both the global level and per-module filters at run time, which turns debugging a deployment into an environment change rather than a rebuild.
Can I use it commercially?
Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 18 days ago.
What is it written in?
Mainly Rust, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.

Editorial analysis

One dependency to add, one variable to set

env_logger is described as a logging implementation for the log crate that is configured via an environment variable, and the usage path is short. The crate goes into the project alongside log, and it must be initialized as early as possible, after which the log macros do the actual work.

console
$ cargo add log env_logger
rust
use log::info;

fn main() {
    env_logger::init();

    info!("starting up");

    // ...
}

The payoff is that the verbosity is decided when the program runs rather than when it is built.

bash
$ RUST_LOG=info ./main
[2018-11-03T06:09:06Z INFO  default] starting up

The README is clear about where this belongs. env_logger makes sense in executables, binary projects, and libraries should use the log crate instead, since a library that installs a global logger takes a decision away from the application that eventually links it.

Level names are case insensitive, and the crate has a house convention

The levels that may be specified correspond to the log::Level enum from the log crate, which are error, warn, info, debug and trace, plus the pseudo level off that disables all logging for a given module or for the entire application. Letter case is not significant, so debug, DEBUG and dEbuG all name the same level, and the example above could equally have been written with INFO. The README then states a house rule, that the project convention is to use lower case names, and explains that other forms appear in the docs only in specific examples so you will not be surprised by similar usage in the wild. That is a small detail, and it is the kind of detail that makes a crate's documentation feel considered rather than assembled.

Filters are per module, which is what makes it useful in a codebase

The per-module filter is the feature that separates env_logger from a global on or off switch, and the README demonstrates it with a module named my_lib.

bash
$ RUST_LOG=my_lib=info cargo test

That runs the tests and shows only the info messages from my_lib, with the output showing the module path on each line, for example INFO my_lib and INFO my_lib::tests, so a test nested inside the module is still matched. The example also makes a point about tests that is easy to miss and expensive to rediscover. env_logger::try_init() needs to be called in each test where you want logging enabled, and because the default behaviour is to run tests in parallel, the logging output may interleave with the test output. The remedies are given, either RUST_TEST_THREADS=1 or naming a single test as an argument.

bash
$ RUST_LOG=my_lib=info cargo test it_adds_one

For a test the crate is added as a dev dependency rather than a normal one.

The builder changes the target, and the default format is explicitly unstable

Logging goes to stderr by default, and the Builder type lets you change that, for instance to stdout, which matters for a CLI whose stdout is piped into another program.

rust
use std::env;
use env_logger::{Builder, Target};

let mut builder = Builder::from_default_env();
builder.target(Target::Stdout);

builder.init();

The stability section is the one to read before you build a pipeline on top of this. The default format will not optimise for long-term stability and explicitly makes no guarantees about the stability of its output across major, minor or patch version bumps during 0.x. The advice is to use a custom format if you intend to capture or interpret the output programmatically. The examples directory reflects that, with files for a custom default format, a custom format, filters built from code, a direct logger, millisecond timestamps since init and a syslog friendly format, so the extension points are there rather than invented.

A workspace with a strict lint policy and a dual licence

The Cargo.toml shows the project is a workspace with resolver 2 and members under crates/, and the workspace package metadata sets the licence as MIT OR Apache-2.0, which explains why the root carries both LICENSE-MIT and LICENSE-APACHE files. The edition is 2021 with a minimum supported Rust version of 1.71, and the include list is deliberately narrow, naming build.rs, src, the manifest, the lock file, the licences, the readme and the examples. The lint configuration is extensive and mostly set to warn, with rust_2018_idioms enabled and a long list of clippy rules including unnameable_types, unsafe_op_in_unsafe_fn, unused_qualifications and cast_possible_truncation, while a small number of rules are allowed outright, with the comment that some explicitly written arrays are better. The repository also carries a deny.toml for dependency policy, a .clippy.toml, a pre-commit configuration, an AI_POLICY.md and a release.toml.

Released regularly, with the version line still in 0.x

The release history shows v0.11.11 on 2026-06-25, v0.11.10 on 2026-03-23 and v0.11.9 on 2026-02-11, and the last push to the repository was on 2026-10-05 with the repository not archived. The rate is roughly one patch every few weeks, which for a crate this widely depended on is a meaningful maintenance signal, and the CHANGELOG.md and committed.toml at the root suggest the release process is automated. The 0.x version number is the one caveat, and the README connects the two facts, since the no-stability-guarantee statement is explicitly scoped to the 0.x series. As long as you are not parsing the default output, the version line is not a practical concern.

Editorial conclusion

env_logger fits a Rust binary or command line tool that needs logging with no configuration file and no code changes, because the RUST_LOG variable controls both the global level and per-module filters at run time, which turns debugging a deployment into an environment change rather than a rebuild. It is a poor fit for a library, since the README is explicit that libraries should depend on log only and let the final binary pick the implementation, and a poor fit if you intend to parse the output, because the default format carries no stability guarantee across versions. Verify first which log facade version your dependency tree uses, since the crate follows the log crate's Level enum, and use the builder with a custom format if anything downstream will consume the output.

Frequently asked questions

Should a Rust library depend on env_logger?

No. The README states that env_logger makes sense in executables and that libraries should use the log crate instead, since the application that links a library is the right place to choose the logging implementation.

How do I set the log level in env_logger?

With the RUST_LOG environment variable. You can give a global level such as RUST_LOG=info, and the five levels correspond to the log::Level enum, error, warn, info, debug and trace, plus the pseudo level off which disables logging for a module or for the whole application.

How do I log to stdout instead of stderr with env_logger?

Use the Builder, creating it from the default environment and setting the target to Target::Stdout before calling init on it.

Can I rely on the env_logger output format staying the same?

No. The README states the default format makes no guarantees about stability across major, minor or patch version bumps during 0.x, and advises using a custom format if you want to capture or interpret the output programmatically.

Official sources

  1. License: Apache-2.0
  2. Project website
  3. README
  4. Releases
  5. rust-cli/env_logger on GitHub
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/rust-cli-env-logger.svg)](https://hysenlabs.com/projects/rust-cli-env-logger)

Was this useful?