How to Debug Connection Issues Using Qlog Tracing in iroh

Enable the qlog feature in your Cargo.toml, set IROH_TEST_QLOG=1 and QLOGDIR=/path/to/logs, then use QlogFileGroup to generate per-connection JSON traces that capture packet-level QUIC events for analysis.

When connections stall, reconnect repeatedly, or exhibit unexpected latency in the iroh peer-to-peer networking stack, qlog tracing provides the protocol-level visibility needed to diagnose root causes. This guide demonstrates how to activate and configure Qlog recording in iroh to capture detailed QUIC transport events—such as packet transmissions, path migrations, and handshake steps—into analyzable trace files according to the n0-computer/iroh source code.

Enable the Qlog Feature in iroh

The Qlog integration in iroh is gated behind the qlog Cargo feature and must be explicitly enabled at compile time. Add the feature to your dependency in Cargo.toml or pass it via command line:

iroh = { version = "0.x", features = ["qlog"] }

The feature gate is checked throughout the codebase via #[cfg(feature = "qlog")], including in iroh/src/endpoint/quic.rs (lines 9–11), where conditional compilation wraps the Qlog-specific transport builder methods.

Configure Environment Variables for Tracing

Runtime configuration relies on two environment variables to control output generation and file destinations:

  • IROH_TEST_QLOG=1 — Enables Qlog generation for any QlogFileGroup created during execution.
  • QLOGDIR=/path/to/logs — Specifies the directory where trace files are written. If unset, no files are emitted. The directory is created automatically if it does not exist.

According to the source code in iroh/src/test_utils/qlog.rs (lines 62–84), the QlogFileGroup::create method checks IROH_TEST_QLOG while the internal QlogFileFactory reads QLOGDIR to determine the output path.

Create a QlogFileGroup for Connection Logging

The QlogFileGroup struct defined in iroh/src/test_utils/qlog.rs (lines 30–45) bundles a common output directory, title prefix, and start timestamp. Instantiate it programmatically or via environment variables:

use iroh::test_utils::QlogFileGroup;

// Create a group writing to ./qlog with prefix "my_test"
let qlog = QlogFileGroup::new("./qlog", "my_test");

// Alternative: read configuration from environment variables
let qlog = QlogFileGroup::from_env("my_test");

Calling create("client") on this group returns a QuicTransportConfig preconfigured to write traces for that specific connection endpoint.

Integrate Qlog with QuicTransportConfig

The builder methods in iroh/src/endpoint/quic.rs (lines 549–579) provide three ways to inject Qlog recording into your transport configuration:

  • qlog_factory(factory) — Accepts a custom Arc<dyn QlogFactory> implementation for advanced use cases.
  • qlog_from_env(prefix) — Automatically reads QLOGDIR and configures the factory based on environment variables.
  • qlog_from_path(path, prefix) — Writes traces directly to a specified directory path.

Typical usage mirrors the pattern found in iroh/examples/transfer.rs:

use iroh::endpoint::{Endpoint, QuicTransportConfig};

let mut cfg = QuicTransportConfig::builder();

// Enable Qlog via environment variables
cfg = cfg.qlog_from_env("my_connection");

// Or target a specific folder directly:
// cfg = cfg.qlog_from_path("./logs/qlog", "my_connection");

let transport = cfg.build();
let endpoint = Endpoint::builder()
    .transport_config(transport)
    .bind()?;

Generate and Analyze Qlog Output

Execute your application with the Qlog feature enabled and environment variables set:

export IROH_TEST_QLOG=1
export QLOGDIR=/tmp/iroh_qlog
cargo run --features qlog --example transfer

This produces JSON-formatted trace files such as:


/tmp/iroh_qlog/transfer.client-2023-05-01-12-00-00.qlog
/tmp/iroh_qlog/transfer.server-2023-05-01-12-00-00.qlog

Each file contains a JSON array of events following the Qlog specification. Analyze these entries to identify specific failure modes:

  • Handshake stages — Look for client_handshake_start and server_handshake_complete. Missing or delayed stages often indicate NAT traversal problems.
  • Path migrations — Entries like path_created and path_removed reveal multipath activity or path drops.
  • Loss and congestionpacket_lost and congestion_event entries help pinpoint bandwidth or buffer-size misconfigurations.
  • Transport parameters — The initial transport_parameters block shows advertised settings such as max_idle_timeout and max_concurrent_multipath_paths.

Complete Example Implementation

Combine these elements into a minimal client that records Qlog traces:

use iroh::endpoint::{Endpoint, QuicTransportConfig};
use iroh::test_utils::QlogFileGroup;
use std::error::Error;

fn main() -> Result<(), Box<dyn Error>> {
    // Initialize Qlog group (writes to ./qlog)
    let qlog = QlogFileGroup::new("./qlog", "demo");
    
    // Create transport configuration with Qlog enabled
    let transport = qlog.create("client")?;
    
    // Build endpoint with tracing configuration
    let endpoint = Endpoint::builder()
        .transport_config(transport)
        .bind()?;
    
    // Initiate connection (replace with actual node address)
    let _conn = endpoint.connect("iroh://example.com:443".parse()?)?;
    println!("Connection initiated – Qlog files available in ./qlog");
    Ok(())
}

For environment-variable-based configuration without code changes, use qlog_from_env:

let cfg = QuicTransportConfig::builder()
    .qlog_from_env("my_connection")
    .build();

Summary

  • Enable the qlog Cargo feature in Cargo.toml to compile Qlog support into iroh.
  • Set IROH_TEST_QLOG=1 and QLOGDIR environment variables to activate runtime tracing.
  • Use QlogFileGroup from iroh/src/test_utils/qlog.rs to manage output directories and generate per-connection configurations.
  • Inject Qlog configurations into QuicTransportConfig via qlog_from_env(), qlog_from_path(), or qlog_factory().
  • Analyze generated JSON traces for handshake failures, path migrations, and congestion events to diagnose connection stalls.

Frequently Asked Questions

What is Qlog and why does iroh use it?

Qlog is a standardized JSON-based tracing format for QUIC and HTTP/3 events. Iroh uses Qlog to record detailed transport-layer activity—packet sends, acknowledgments, loss detection, and path changes—enabling developers to debug complex connection issues that standard application logging cannot capture.

Do I need to modify my code to enable Qlog tracing in iroh?

Not necessarily. While you can programmatically create a QlogFileGroup and call create() to generate a QuicTransportConfig, you can also use the qlog_from_env() method to read the QLOGDIR and IROH_TEST_QLOG variables automatically, requiring no hardcoded paths in your application.

Where are the Qlog trace files stored?

Trace files are written to the directory specified by the QLOGDIR environment variable. If the directory does not exist, iroh creates it automatically. Each file follows the naming pattern {prefix}.{identifier}-{timestamp}.qlog, as implemented in iroh/src/test_utils/qlog.rs.

How do I view and analyze Qlog files?

Open the JSON trace files in dedicated Qlog viewers such as the Qlog viewer or cattrace. These tools visualize packet timelines, handshake progression, and congestion events, allowing you to correlate transport behavior with application-level connection issues.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →