Framework
estk/log4rs avatar
estk/log4rs

log4rs: a YAML-driven logging backend for the Rust log facade

A highly configurable logging framework for Rust

1,134 stars167 forksRustApache-2.0

At a glance

What is it?
log4rs is a Rust logging framework modelled on Java's Logback and log4j, where appenders, levels and loggers live in a YAML file instead of Rust code. It is a good fit for services that need file rotation and JSON output, and a poor fit for projects that want a single println-style backend with no configuration layer.
Who is it for?
log4rs earns its place in a Rust service that needs structured output, per-module levels and file rotation without hand written plumbing. It is a poor match for a small binary, a library crate, or a team that would rather not ship a YAML file next to the executable.
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 3 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

Appenders, loggers and levels live in one YAML file

The unit of configuration in log4rs is a YAML document, not Rust code. The Quick Start configuration opens with `refresh_rate: 30 seconds` and then declares two appenders: a console appender named `stdout` and a file appender named `requests` writing to `log/requests.log`. Underneath, the `root` logger sits at level `warn` and forwards to `stdout`, while two module paths, `app::backend::db` and `app::requests`, are lowered to `info` so that more verbose records from those modules survive the root threshold. This is the familiar ancestor-child model: a level set on a module path overrides the root level for records logged from that path. The `app::requests` logger also lists the `requests` appender and sets `additive: false`, which stops those records from travelling up to the root appender as well, so the same event does not appear twice on the console. Each appender carries its own encoder, here a `pattern` of `{d} - {m}{n}` for the date, the message and a newline. The practical consequence is that level changes and file routing become an operator concern rather than a code concern, which is the reason teams reach for a log4j style framework in the first place.

init_file is the only call your main function needs

Wiring the configuration into a program takes one function. The quick start example imports the macros from the `log` crate and calls `log4rs::init_file("config/log4rs.yaml", Default::default())`, which reads the document from disk, builds the appenders and installs the resulting logger. Because the call sites use `info!` and friends from `log`, application code has no dependency on log4rs at all beyond that single setup call, and the crate describes itself as a multi-output logging implementation for the `log` facade. The second argument to `init_file` is a configuration object, and the quick start passes `Default::default()`, which is the simplest way to get a working logger. The crate is published on crates.io under the name `log4rs`, and adding it to a project is a single dependency line. The version in the repository is 1.4.0, so the manifest entry below is the one to copy into your own Cargo.toml.

toml
[dependencies]
log4rs = "1.4.0"

The quick start does not spell out a registry command line, so the crates.io listing linked from the README badge is where the published versions and feature flags are described. The example deliberately elides the rest of the program after the first `info!` call, which tells you the framework needs no further per-call ceremony.

Rolling archives are compressed on the calling thread

The documented sharp edge in log4rs is compression during file rotation. When the file appender rolls an archive and the `gzip` or `zstd` feature is enabled, the archive is zipped automatically, and the project documentation states plainly that the zip process happens in the main thread and halts the process until it completes. The problem scales with archive size, so a service that rolls large files sees latency spikes and stalled request handling at the worst possible moment. Three mitigations are named in the documentation. Enabling the `background_rotation` feature spawns an operating system thread to perform the compression instead of the caller. Leaving both `gzip` and `zstd` disabled removes the compression step entirely. Or you keep archives small enough that the compression time is acceptable, which is a sizing decision rather than a code change. The `background_rotation` feature is not part of the default feature set in Cargo.toml, so picking it is an explicit act. If your retention policy requires compressed archives, read this section twice before choosing the appender.

Cargo features decide which half of the framework you compile

log4rs ships as a set of optional Cargo features, and the default set is broad: `all_components`, `config_parsing`, `yaml_format` and `parking_lot`. `all_components` pulls in the console, file and rolling file appenders, the compound policy, the delete and fixed window rollers, the size and time triggers, the startup trigger, the JSON and pattern encoders and the threshold filter. That is a lot of machinery for a program that only wants a console line. The dependency list behind these features is correspondingly wide, with `arc-swap`, `chrono`, `serde`, `serde-value` and `typemap-ors` for configuration parsing, and `serde-saphyr` for the YAML format. Alternative format features exist, `json_format` on `serde_json` and `toml_format` on `toml`, so a deployment that keeps configuration in JSON can turn the YAML support off. The crate version in Cargo.toml is 1.4.0, and the published release list shows v1.4.0 dated 2025-09-05 with a release candidate in May of the same year and v1.3.0 in February 2024. Pinning features deliberately is the single most effective way to keep this dependency small.

A pattern encoder or a JSON encoder, and no mixing of the two

The choice of encoder decides the shape of every record, and the two options differ in cost. The `pattern_encoder` feature needs `chrono`, `log-mdc` and `thread-id`, and it produces the formatted text described by the pattern, which in the quick start is `{d} - {m}{n}`. The `json_encoder` feature adds `serde`, `serde_json`, `chrono`, `log-mdc`, `log/serde` and `thread-id`, so it costs an extra serialisation dependency and a derived structure in exchange for machine readable output. Because the `log` facade supports structured key and value pairs, and the v1.4.0 release is titled for key value support, the JSON path is the one to pick when a log aggregator is downstream. The `log_kv` feature enables `log/kv` and `log/kv_serde` in the facade, which is what makes those key and value pairs available in the first place. If you are only reading logs by eye in a terminal, the pattern encoder keeps the dependency graph smaller. Choose one and configure the appender to use it, rather than assuming both are available to every appender.

Wasm targets need the getrandom backend set explicitly

Building log4rs for a WebAssembly target has one extra step, and it is a step that is easy to miss because it fails at build time rather than at run time. If you build with the `time_trigger` feature enabled, the documentation requires the compiler flag `--cfg getrandom_backend="wasm_js"`. The documentation also notes this should be automatic when compiling with Cargo, but that some configurations and tooling need the setting supplied by hand, in which case the environment variable `RUSTFLAGS` carries the value. The `time_trigger` feature depends on `rand` and `getrandom`, which is where the requirement originates. The `time_trigger` feature belongs to the default set through `all_components`, so a default build for Wasm is exactly the case that needs the flag. If your Wasm target is a short lived browser page, a time based rotation trigger is often unnecessary, and dropping the feature removes the constraint along with the dependency.

Two licences, an active branch and a repository with no homepage

log4rs is offered under the dual licence of Apache License 2.0 and MIT, at your option, with the licence files LICENSE-APACHE and LICENSE-MIT at the root of the repository. The README states that unless a contribution says otherwise, contributions are dual licensed the same way, with no additional terms or conditions, which keeps the licensing surface uniform for anyone who contributes. The repository records the licence as Apache-2.0, and Cargo.toml states `MIT OR Apache-2.0`. The repository is not archived, and the last push was on 2026-10-19, so this is a project receiving current work rather than a frozen one. The last releases are dated well before that push, v1.4.0 on 2025-09-05 and v1.3.0 on 2024-02-10, so the gap between the newest published tag and the newest commit is worth checking against your own release expectations. There is no homepage listed, and the entry point for information is the README, the `docs/` directory, the `examples/` directory and the API documentation on docs.rs. The example files show the range of what is possible without patching the crate, including `compile_time_config.rs`, `custom.rs`, `custom_config.rs`, `json_logger.rs`, `log_to_file.rs` and rolling file examples driven by both size and time triggers.

When a plain log facade backend is the better choice

The alternative to log4rs is not another framework but a decision to stop configuring logging at all. The `log` facade alone, with a minimal backend that writes one line per record, needs no YAML file, no appender registry, no encoder choice and no rotation policy. The difference in approach is exactly what log4rs adds: routing, thresholds, structured output and archive management, all declared outside the program and reloadable on a refresh interval. That is a real advantage for a service running for weeks, and a real cost for a build step, a command line tool or a library crate where a caller should decide about logging instead of the library. The point of comparison is not that either side is better. A trading desk writing JSON records into a collector wants the key value support and the JSON encoder, and pays for the feature set to get there. A small binary that prints diagnostics to a terminal pays for that same feature set and gets nothing back. The compression caveat and the rustc 1.89 floor are also differentiators, since a minimal backend has neither.

Editorial conclusion

log4rs earns its place in a Rust service that needs structured output, per-module levels and file rotation without hand written plumbing. It is a poor match for a small binary, a library crate, or a team that would rather not ship a YAML file next to the executable. Before adopting it, check three things: that rustc 1.89 or newer is available in your build image, that you can tolerate a dependency set that grows with the features you enable, and that you know which of gzip, zstd or background_rotation your rotation path actually uses, because the default file appender compresses on the main thread.

Frequently asked questions

What Rust version does log4rs require?

Cargo.toml sets `rust-version = "1.89"` and the README lists 1.89 as the minimum rustc version, with a badge on the same page reflecting the same floor.

How do I add log4rs to a Rust project and start logging?

No cargo add command is given in the project documentation, so take the crate from the crates.io listing linked in its badge. The quick start then expects a YAML file such as `config/log4rs.yaml` and one call, `log4rs::init_file("config/log4rs.yaml", Default::default())`, after which the `log` macros such as `info!` work as usual.

Does log4rs support JSON output and file rotation?

Yes, as opt-in Cargo features. JSON comes from the `json_format` and `json_encoder` features, and rotation comes from `rolling_file_appender` combined with `size_trigger`, `time_trigger` and `fixed_window_roller`, with `delete_roller` for cleanup.

How do I build log4rs for a WebAssembly target?

With the `time_trigger` feature enabled, the compiler must be given the getrandom wasm backend, normally through the RUSTFLAGS environment variable, and the documentation notes that Cargo usually supplies it automatically but some tooling configurations do not.

Is there a known performance problem with log4rs file rotation?

There is a documented one. With the `gzip` or `zstd` feature enabled, archives are compressed on the main thread, which halts the process until the zip completes, and the documentation names `background_rotation` as one way to move that work to a separate thread.

Official sources

  1. estk/log4rs on GitHub
  2. Issues
  3. License: Apache-2.0
  4. README
  5. Releases
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/estk-log4rs.svg)](https://hysenlabs.com/projects/estk-log4rs)

Was this useful?