Rust Log or Tracing?
log and tracing are two facades for recording what a program does. tracing adds spans and fields to the same idea.
Old lines, new stream
After the fmt subscriber starts, a plain log line prints in tracing dress. The word bridge is the target โ the module path of this program:
log::info!("an old log line from the library");Both macros, one output
A tracing line from the same program lands right beside it, in the same shape:
tracing::info!("a new tracing line");Levels cross the bridge too
The bridge keeps the level. A debug line from the log crate arrives as a DEBUG event:
log::debug!("old style debug detail");A library picks a facade, not a printer
Either import gives the same macro names. The library never learns which printer the program chose:
use log::info;
// or, in a tracing library:
use tracing::info;Example
// Cargo.toml: log = "0.4" (resolved 0.4.34), tracing = "0.1" (resolved 0.1.44),
// tracing-subscriber = "0.3" (resolved 0.3.23)
fn main() {
tracing_subscriber::fmt()
.with_max_level(tracing::Level::DEBUG)
.without_time()
.with_ansi(false)
.init();
log::info!("an old log line from the library");
tracing::info!("a new tracing line");
log::debug!("old style debug detail");
}Key points
- log is the smaller tool: five macros, levels, and nothing else.
- It fits libraries and small programs well
- tracing adds spans and fields to the same five levels.
- Pick it when one run must explain a whole request, not single moments
- The two facades share the road.
- tracing-subscriber catches log records.
- It prints them as events.
- So old and new code land in one stream.
- That bridge rides inside tracing-subscriber by default, through its tracing-log feature.
- Installing a second bridge by hand fails at startup, because the log crate allows only one logger
- A library should depend on a facade only: log or tracing.
- The final program installs the logger or the subscriber.
In this example, the program is a crate called bridge, and nobody calls a bridge setup line. The fmt subscriber starts, and the log lines simply arrive. tracing-subscriber carries the tracing-log bridge in its default features. So it registers a log logger. That logger forwards every record as an event. The target stays visible in this output on purpose. All three lines carry the same target, bridge. All three were written in this crate. One warning from real life: install the bridge twice and the second install fails. The log crate keeps one logger seat, and the fmt subscriber already took it.
Note
Moving from log to tracing needs no rewrite of old call sites.
The macros share names and levels, and the bridge carries the old lines until you upgrade them.
Try it Yourself
Edit the code, then press Run.
Running is simulated ยท Rust Playground
Exercise
A library you depend on logs with the log crate. Your program uses tracing. What happens to the library's lines?