Axum

Set up debugger in a Rust project using the Axum framework.

Last updated March 19, 2026

Rust + Axum

This guide covers adding debugger to a Rust API using Axum. The setup takes three lines.

Axum official docs

Feature Support
Server console Yes
Server errors Via tracing
HTTP requests Yes
Browser script injection Manual

Prerequisites

  • Rust 1.75 or later

Install

Add the crate to your Cargo.toml:

[dependencies]
ephem-debugger = { version = "0.1", features = ["axum"] }

Set up

Use the layers convenience function to get both the HTTP middleware and tracing capture layer:

use axum::{routing::get, Json, Router};
use ephem_debugger::axum_middleware;
use serde_json::{json, Value};
use tracing_subscriber::prelude::*;

async fn index() -> Json<Value> {
    tracing::info!("home page hit");
    Json(json!({"status": "ok"}))
}

#[tokio::main]
async fn main() {
    let (middleware_layer, capture_layer) = axum_middleware::layers(3000);

    tracing_subscriber::registry()
        .with(capture_layer)
        .with(tracing_subscriber::fmt::layer())
        .init();

    let app = Router::new()
        .route("/", get(index))
        .layer(middleware_layer);

    let listener = tokio::net::TcpListener::bind("0.0.0.0:3000")
        .await.unwrap();
    axum::serve(listener, app).await.unwrap();
}

Three lines handle debugger setup:

  1. axum_middleware::layers(3000) — creates the session, store, IPC bridge, and returns both layers
  2. .with(capture_layer) — captures all tracing events into the debugger store
  3. .layer(middleware_layer) — captures HTTP request metadata

What gets captured

  • HTTP requests — method, path, status code, and duration for every request via the Tower middleware layer
  • tracing events — all tracing::info!(), tracing::error!(), etc. calls via the capture layer, including structured fields
  • Axum internals — connection events at DEBUG/TRACE level

Verify

Build and run:

cargo run

The terminal shows the session ID:

> @ephem-sh/debugger: session ba2f3c
> @ephem-sh/debugger: bridge listening on 127.0.0.1:60693

Open another terminal and query:

npx dbg status
pnpm dlx dbg status
bun x dbg status
yarn dlx dbg status
npx dbg server console
pnpm dlx dbg server console
bun x dbg server console
yarn dlx dbg server console

API reference

axum_middleware::layers(port) -> (DebuggerLayer, CaptureLayer)

Returns a tuple of two layers:

  • DebuggerLayer — Tower Layer for HTTP request capture
  • CaptureLayertracing_subscriber::Layer for log capture

Add the DebuggerLayer to your Axum Router with .layer() and the CaptureLayer to your tracing_subscriber::registry() with .with().

DebuggerLayer::new(port) -> DebuggerLayer

Creates just the HTTP middleware layer (without tracing capture). Use this if you want to set up tracing separately.

Production safety

The middleware runs unconditionally. Guard it with a feature flag or environment variable:

let app = if std::env::var("DEBUG").is_ok() {
    let (mw, cap) = axum_middleware::layers(3000);
    // set up tracing with cap...
    router.layer(mw)
} else {
    router
};

Browser support

The middleware automatically handles /_/d.js and /_/d POST routes. To enable browser capture, add these script tags before </body> in your HTML templates:

<script>window.__DEBUGGER_INGEST_URL__="/_/d";</script>
<script src="/_/d.js" defer></script>

Query browser data with:

npx dbg browser console
pnpm dlx dbg browser console
bun x dbg browser console
yarn dlx dbg browser console
npx dbg browser errors
pnpm dlx dbg browser errors
bun x dbg browser errors
yarn dlx dbg browser errors
npx dbg browser network
pnpm dlx dbg browser network
bun x dbg browser network
yarn dlx dbg browser network
npx dbg browser storage
pnpm dlx dbg browser storage
bun x dbg browser storage
yarn dlx dbg browser storage

Full example

See the complete working example at examples/rust/axum.

Search Documentation

Search for pages and content