Logging and Observability
Rule
Use tracing with operation spans, structured fields, fixed messages, sparse high-signal events, and explicit redaction.
Why
Structured traces remain searchable and aggregatable, while fixed messages identify event kinds and fields carry per-operation data.
Do
- Let applications configure subscribers; libraries emit only spans and events.
- Add spans around requests, jobs, commands, tasks, external calls, and workflow steps.
- Prefer
#[tracing::instrument(skip_all, fields(...))]and opt fields in. - Put IDs, states, attempts, counts, and durations in snake_case fields.
- Keep INFO for lifecycle and important outcomes, DEBUG for investigation, WARN for degradation, and ERROR for failed operations.
- Record errors with Debug capture (
error = ?err) or a&dyn Errorfield. - Use counts, hashes, redacted displays, or booleans instead of sensitive raw values.
Avoid
- Do not interpolate variable data into message strings.
- Do not emit duplicate or high-cardinality INFO events.
- Do not initialize subscribers in reusable libraries.
- Do not use tracing as user-facing output or durable business events.
- Do not use bare
#[instrument]on arguments that may contain secrets. - Do not log credentials, tokens, bodies, raw command output, or unredacted URLs.
Library vs Application
Libraries emit structured telemetry without choosing global formatting or filtering. Applications own destinations, propagation, and subscriber configuration.
Example
#![allow(unused)]
fn main() {
#[tracing::instrument(skip_all, fields(account_id = %account_id))]
pub async fn sync_account(
account_id: AccountId,
client: &BillingClient,
) -> Result<(), SyncError> {
let invoices = client.list_invoices(account_id).await.map_err(|err| {
tracing::error!(error = ?err, "account sync failed");
SyncError::ListInvoices(err)
})?;
tracing::info!(invoice_count = invoices.len(), "account sync complete");
Ok(())
}
}
Exceptions
- Send CLI output through the command output path; justify direct printing with a local lint expectation.
- Temporarily add DEBUG detail during investigation, then retain only durable signal.
- Use metrics or durable events for alerts, billing, audit, or product behavior.