rust
48 lines · 7 steps
Structured request tracing in Axum
Wire a TraceLayer into an Axum router to emit a structured span for every HTTP request.
Explained by
highlit
1use std::time::Duration;
2
3use axum::{
4 body::Body,
5 extract::MatchedPath,
6 http::{Request, Response},
7 routing::get,
8 Router,
9};
10use tower_http::trace::TraceLayer;
11use tracing::{info_span, Span};
12
13pub fn app() -> Router {
14 Router::new()
15 .route("/health", get(|| async { "ok" }))
16 .route("/users/:id", get(get_user))
17 .layer(
18 TraceLayer::new_for_http()
19 .make_span_with(|request: &Request<Body>| {
20 let matched_path = request
21 .extensions()
22 .get::<MatchedPath>()
23 .map(MatchedPath::as_str);
24
25 info_span!(
26 "http_request",
27 method = %request.method(),
28 uri = %request.uri(),
29 matched_path,
30 request_id = %uuid::Uuid::new_v4(),
31 )
32 })
33 .on_response(|response: &Response<Body>, latency: Duration, _span: &Span| {
34 tracing::info!(
35 status = response.status().as_u16(),
36 latency_ms = latency.as_millis(),
37 "request completed"
38 );
39 })
40 .on_failure(|error, latency: Duration, _span: &Span| {
41 tracing::error!(
42 %error,
43 latency_ms = latency.as_millis(),
44 "request failed"
45 );
46 }),
47 )
48}
01 / 01
STEP 01
‹ swipe to step through ›
Walkthrough
Space play
←→ step
click any line
Three takeaways
- 1A single tower layer can instrument every route without touching individual handlers.
- 2Reading MatchedPath keeps span labels low-cardinality by grouping requests under their route template.
- 3Separate hooks for span creation, success, and failure give you full-lifecycle observability per request.
Related explainers
rust
use std::cmp::Ordering; pub struct PrefixIndex { entries: Vec<String>,
Prefix search with binary partitioning in Rust
binary-search
sorting
case-insensitive
Intermediate
7 steps
javascript
const express = require('express'); const router = express.Router(); const { pool } = require('../db'); const redis = require('../redis');
Building a health check endpoint in Express
health-check
timeouts
promise-race
Intermediate
9 steps
rust
use std::cmp::Ordering; use std::str::FromStr; #[derive(Debug, Clone, PartialEq, Eq)]
Parsing and ordering semantic versions in Rust
parsing
trait-implementation
ordering
Intermediate
8 steps
php
<?php namespace App\Http\Middleware;
Idempotent requests with Laravel middleware
idempotency
middleware
caching
Advanced
8 steps
javascript
'use client'; import { useEffect } from 'react'; import * as Sentry from '@sentry/nextjs';
How a Next.js error boundary recovers
error-boundary
error-handling
observability
Intermediate
8 steps
go
package middleware import ( "net/http"
A maintenance-mode gate in Gin
middleware
atomic-flag
concurrency
Intermediate
8 steps
Share this explainer
Here's the card — post it anywhere.
Made with highlit — turn any snippet into a walkthrough like this in about a minute.
Explain your code
Embed this explainer
Drop the interactive walkthrough into a blog or docs. Views never cost a credit.
<iframe src="https://highlit.co/explainers/structured-request-tracing-in-axum-explained-rust-d021/embed?autoplay=1" width="100%" height="520" loading="lazy" style="border:0"></iframe>
Autoplay is on by default — add ?autoplay=0 to start paused.