Log is span + fields, not println!. Timeouts, health, and process JSON-on-prod: rust-axum-production. Here: API tracing, subscriber, correlation. HTTP layers: tower-http TraceLayer in the axum.
Non-negotiable rules
info!/warn!/error!/debug!with fields (user_id = %id), notformat!("user {}", id)as a single message.- Spans at boundaries (request, job, query).
#[instrument]in async services. - Filter by
RUST_LOG/EnvFilter. Notracefrom a noisy crate in prod (hyper=info). - No PII/secrets (
authorization, login body, CPF).production-readiness. - One subscriber in
main. Notfmt::initagain in the handler.
Subscriber
tracing_subscriber::fmt()
.with_env_filter(EnvFilter::from_default_env())
.json() // produção
.init();
- Dev: compact/pretty. Prod: JSON (
rust-axum-production). tracing-subscriber+tracingaligned versions. OTEL: layer from the repo if one already exists (rust-microservices) — do not invent a parallel stack.
Spans
#[instrument(skip(db), fields(order_id = %id))]
async fn load_order(db: &Db, id: Uuid) { /* */ }
skipin large pools/clients.err/retonly if the type is safe to log.- Axum:
TraceLayer::new_for_http()+spanwithhttp.method,uri,status. Request id: headerx-request-idor generate in middleware. - Tokio: span on the task (
Instrument::instrument) if the job leaves the request.
Levels
| Level | Use |
|---|---|
error |
Failure that needs action; with err |
warn |
Degraded, retry exhausting |
info |
Business event (order created) — sparingly |
debug |
Internal flow |
trace |
Protocol; off in prod |
Not info per SQL query. debug in the repository if needed.
Anti-patterns
dbg!/println!left in the API- Logging
Json<T>entire input - Span per iteration of a hot loop
unwrapin theinitof the subscriber in a lib- Two formats (fmt + json) without a conscious combined
Layerconscious combined
Integration with other skills
- Axum process:
rust-axum-production - Runtime:
tokio - HTTP:
axum - Client:
reqwest(outbound span) - Tests:
rust-unit-testing(do not assert logs unless the crate already tests it)
Completion criteria
- Single subscriber; filter by env
- Structured fields; no secret
- Request span (TraceLayer or equivalent)
instrumentin the services touched- JSON in prod if the service already uses JSON logs