What is tracing and why is it needed?
tracing is a powerful framework for instrumenting and monitoring applications in Rust. Unlike simple logging, tracing provides structured data about program execution, allowing you to track not only messages but also context, spans, and events. This is especially useful for performance diagnostics, distributed systems, and microservices.
Key Features
- Spans: tracking time intervals of operation execution (e.g., processing an HTTP request).
- Events: point logs with context (level, field, time).
- Structured data: support for fields (key-value) for machine processing.
- Asynchrony: full compatibility with tokio and async/await.
- Filtering: dynamic control of logging levels (trace, debug, info, warn, error).
Installation
Add to Cargo.toml:
[dependencies]tracing = "0.1"tracing-subscriber = "0.3"Rust Code Example
use tracing::{info, span, Level};use tracing_subscriber::FmtSubscriber;
fn main() { // Initialize subscriber (output to stdout) let subscriber = FmtSubscriber::builder() .with_max_level(Level::TRACE) .finish(); tracing::subscriber::set_global_default(subscriber) .expect("Failed to set global subscriber");
// Create a span for the operation let span = span!(Level::INFO, "main_operation", user_id = 42); let _guard = span.enter();
// Log an event info!("Starting request processing");
// Nested span let inner_span = span!(Level::DEBUG, "sub_task", task_id = "calc"); let _inner_guard = inner_span.enter(); tracing::event!(Level::TRACE, "Executing subtask"); drop(_inner_guard);
info!("Request completed");}Terminal output (with timestamps and context):
2025-03-22T10:00:00.123Z INFO main_operation{user_id=42}: Starting request processing2025-03-22T10:00:00.124Z TRACE main_operation{user_id=42}:sub_task{task_id="calc"}: Executing subtask2025-03-22T10:00:00.125Z INFO main_operation{user_id=42}: Request completedWhen to use tracing?
- Microservices: tracking request chains through distributed spans (e.g., using opentelemetry).
- High-load systems: replacing standard logging to reduce overhead.
- Debugging async code: spans are automatically attached to tokio tasks.
- Production monitoring: integration with Grafana, Jaeger, Datadog via trace export.
The tracing library is the de facto standard for monitoring in the Rust ecosystem. It is used in projects such as tokio, hyper, actix-web, and axum.