# How to Debug Connection Issues Using Qlog Tracing in iroh

> Debug iroh connection issues with qlog tracing. Enable the qlog feature, set QLOGDIR, and generate per-connection JSON traces with QlogFileGroup for detailed analysis.

- Repository: [number zero/iroh](https://github.com/n0-computer/iroh)
- Tags: how-to-guide
- Published: 2026-06-19

---

**Enable the `qlog` feature in your [`Cargo.toml`](https://github.com/n0-computer/iroh/blob/main/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`](https://github.com/n0-computer/iroh/blob/main/Cargo.toml) or pass it via command line:

```toml
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`](https://github.com/n0-computer/iroh/blob/main/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`](https://github.com/n0-computer/iroh/blob/main/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`](https://github.com/n0-computer/iroh/blob/main/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:

```rust
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`](https://github.com/n0-computer/iroh/blob/main/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`](https://github.com/n0-computer/iroh/blob/main/iroh/examples/transfer.rs):

```rust
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:

```bash
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 congestion** — `packet_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:

```rust
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`:

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

```

## Summary

- Enable the **`qlog`** Cargo feature in [`Cargo.toml`](https://github.com/n0-computer/iroh/blob/main/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`](https://github.com/n0-computer/iroh/blob/main/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`](https://github.com/n0-computer/iroh/blob/main/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](https://github.com/quiclog/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.