| name | rust-logging |
| description | Use when setting up tracing, configuring log levels, writing structured logs, using spans and instrument, or handling sensitive data in Rust logs.
|
Rust Logging Standards
Core Rules
- Framework:
tracing + tracing-subscriber
- Format: pretty print in dev, JSON in production
- Output: stdout
- Language: all log messages in English
Log Levels
| Level | Purpose | Example |
|---|
ERROR | Requires alerting and human intervention | Database connection failed |
WARN | Needs attention but system can self-heal | Retry succeeded after transient failure |
INFO | Business events, visible in production | Order created/completed |
DEBUG | Development debugging, disabled in prod | SQL queries, intermediate values |
TRACE | Extreme detail, only for hard-to-diagnose issues | Function entry/exit |
RUST_LOG=info,my_app=debug
RUST_LOG=debug,my_app=trace,sqlx=warn
Structured Logging
Use snake_case field names:
tracing::info!(
request_id = %request_id,
user_id = %user_id,
order_id = %order.id,
duration_ms = elapsed.as_millis() as u64,
"order completed"
);
Common fields: request_id, user_id, order_id, duration_ms, error, path, method, status
Span Usage
#[tracing::instrument(
name = "create_order",
skip(self, cmd),
fields(user_id = %cmd.user_id, product_id = %cmd.product_id)
)]
pub async fn create_order(&self, cmd: CreateOrderCommand) -> Result<Order, AppError> {
}
- Always
skip large or non-Display arguments (self, request bodies, DB pools).
- Use
fields(...) to attach key context to the span.
Sensitive Data
Never log: passwords, API keys, tokens, credit card numbers, personal IDs.
use secrecy::Secret;
pub struct Config {
pub api_key: Secret<String>,
}
Error Logging
tracing::error!(error = ?err, "database connection failed");
tracing::warn!(error = ?err, attempt = attempt, "retry after failure");
tracing::info!(error = %err, "validation failed");
?err — preserves the full error chain (Debug format)
%err — logs only the Display message
Checklist