Skip to content

rust.missing_tracing

Observability Low

Detects code without tracing instrumentation.

Without distributed tracing:

  • Blind debugging — No visibility into request flow
  • Lost time — Can’t identify where latency comes from
  • Blame games — Can’t tell which service caused the issue
  • Incident chaos — Production problems take hours to diagnose

Tracing is essential for operating distributed systems.

// ❌ Before
async fn handle_request(req: Request) -> Response {
let user = get_user(req.user_id).await;
let data = fetch_data(user.id).await;
process(data).await
}

No visibility into what happened during the request.

// ✅ After
use tracing::{instrument, info};
#[instrument(skip(req))]
async fn handle_request(req: Request) -> Response {
info!(user_id = %req.user_id, "handling request");
let user = get_user(req.user_id).await;
let data = fetch_data(user.id).await;
process(data).await
}
#[instrument]
async fn get_user(user_id: UserId) -> User {
// Automatically creates span with function name and args
}
  • Public async functions without #[instrument]
  • Request handlers without tracing
  • Missing span creation in service boundaries

Unfault adds #[instrument] attributes to functions.

use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt};
fn init_tracing() {
tracing_subscriber::registry()
.with(tracing_subscriber::fmt::layer())
.with(tracing_subscriber::EnvFilter::from_default_env())
.init();
}
// With OpenTelemetry
use tracing_opentelemetry::OpenTelemetryLayer;
use opentelemetry::sdk::trace::TracerProvider;
fn init_otel_tracing() {
let tracer = opentelemetry_jaeger::new_pipeline()
.install_simple()
.unwrap();
tracing_subscriber::registry()
.with(OpenTelemetryLayer::new(tracer))
.init();
}
// Skip large fields
#[instrument(skip(password, body))]
async fn login(username: &str, password: &str) { }
// Add custom fields
#[instrument(fields(request_id = %req.id))]
async fn handle(req: Request) { }
// Error logging
#[instrument(err)]
async fn fallible() -> Result<(), Error> { }