Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Debugging with tokio-console

tokio-console is an interactive task inspector for async Rust applications. It connects to a running ndn-fwd process over gRPC and shows every live tokio task by name, its poll count, idle time, and busy time. This is the right tool when a face is stalling and you want to see which task is hung, or when you want to understand where the forwarder is spending its time.

When to use it

  • A face reader stops receiving packets but the process is running.
  • The pipeline is slow and you need to identify the bottleneck task.
  • An expiry worker appears to have stopped ticking.
  • You want to verify that NLSR’s recompute loop is firing as expected.

Build

RUSTFLAGS="--cfg tokio_unstable" \
  cargo build -p ndn-fwd --features console --profile console

The --cfg tokio_unstable flag enables tokio’s internal task instrumentation hooks. This is not optional — without it, tokio does not expose task data to console-subscriber and the tool will show no tasks. The console Cargo profile inherits dev settings and keeps debug symbols.

The long-lived task spans shipped in phase 2 name every persistent task so tokio-console shows rows like engine_task, face_read, face_write, expiry, pipeline_dispatch, nlsr_sync, and nlsr_recompute rather than anonymous tokio::spawn[…] entries.

The console layer listens on 127.0.0.1:6669 by default. Override with:

TOKIO_CONSOLE_BIND=0.0.0.0:9999 \
  RUSTFLAGS="--cfg tokio_unstable" \
  cargo run -p ndn-fwd --features console --profile console

Install tokio-console

cargo install --locked tokio-console

Connect

tokio-console

With a custom bind address:

tokio-console http://127.0.0.1:9999

Expected output

After connecting, the task list pane shows one row per live task. The Name column will contain the span names set in phase 2:

 ID  Name                  State   Total  Busy    Idle    Polls
  1  engine_task           idle    1.2s   0.001s  1.199s      4
  2  expiry (pit)          idle    1.2s   0.000s  1.200s    120
  3  expiry (rib)          idle    1.2s   0.000s  1.200s      1
  4  expiry (idle_face)    idle    1.2s   0.000s  1.200s      0
  5  pipeline_dispatch     idle    1.2s   0.001s  1.199s     64
  6  face_read  (face_id=1) idle   1.2s   0.001s  1.199s      8
  7  face_write (face_id=1) idle   1.2s   0.000s  1.200s      2

If you see only tokio::spawn[…] rows, the binary was not built with --cfg tokio_unstable or the console feature was not enabled.

Production note

The --features console build is a debugging build, not for production use. The overhead of --cfg tokio_unstable is small (a few extra atomic operations per task poll) but measurable under high packet rates. The long-lived task spans (added unconditionally in phase 2) have no runtime cost beyond the tracing::Span the process already pays; only the console gRPC server is gated behind the feature flag.