Cogs and Levers A blog full of technical stuff

tracing

println! debugging scales poorly. Traditional logging is better — but in async systems, logs alone aren’t enough. You need structured context.

That’s what tracing provides.

What Problem Does tracing Solve?

Structured, contextual logging with:

  • Spans
  • Events
  • Fields
  • Async awareness

It models execution flow.

Minimal Example

Cargo.toml

[dependencies]
tracing = "0.1"
tracing-subscriber = "0.3"

main.rs

use tracing::{info, span, Level};
use tracing_subscriber;

fn main() {
    tracing_subscriber::fmt::init();

    let span = span!(Level::INFO, "startup", version = "1.0");
    let _enter = span.enter();

    info!("application started");
}

This prints structured logs with metadata.

What’s Actually Happening?

tracing separates:

  • Instrumentation (in your code)
  • Subscribers (output behavior)

This means:

  • Logs
  • JSON output
  • Distributed tracing
  • Metrics

All can be layered without rewriting call sites.

Where It Fits

Use tracing when:

  • You write async services
  • You need request-scoped context
  • You care about observability

It shines with Tokio.

Trade-offs

Pros

  • Structured fields
  • Async-aware
  • Pluggable backends

Cons

  • More complex than log
  • Requires setup

Should You Use It?

If your system has concurrency or complexity:

Yes.

Logs without context are noise.