# How to Debug Connection Issues Using iroh’s Qlog Integration

> Debug iroh connection issues with qlog integration. Capture QUIC traces to reveal handshake failures, path migrations, and congestion events. Enable qlog and set environment variables for detailed insights.

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

---

**Enable the `qlog` Cargo feature, set the `IROH_TEST_QLOG=1` and `QLOGDIR` environment variables, and instantiate a `QlogFileGroup` to capture detailed QUIC protocol traces that reveal handshake failures, path migrations, and congestion events.**

The `iroh` networking library from n0-computer provides built-in **Qlog** support that records granular QUIC transport events into standardized JSON files. When you need to debug connection issues using iroh's qlog integration, you can generate protocol-level traces that show exactly when packets are sent, received, or lost, enabling precise diagnosis of stalled or unstable connections.

## Enable the Qlog Feature

Qlog support is conditionally compiled via the `qlog` feature flag. To access the tracing APIs, add the feature to your `iroh` dependency in [`Cargo.toml`](https://github.com/n0-computer/iroh/blob/main/Cargo.toml):

```toml
iroh = { version = "0.XX", features = ["qlog"] }

```

The codebase guards Qlog functionality with `#[cfg(feature = "qlog")]` checks. In [`iroh/src/endpoint/quic.rs`](https://github.com/n0-computer/iroh/blob/main/iroh/src/endpoint/quic.rs) (lines 9‑11), the transport builder conditionally exposes debugging methods, with the full implementation of builder helpers appearing at lines 549‑579.

## Configure Environment Variables

Runtime Qlog generation requires two environment variables:

- **`IROH_TEST_QLOG=1`** – Required to enable trace generation for any `QlogFileGroup` instance.
- **`QLOGDIR`** – Specifies the output directory for trace files. If unset, no logs are emitted. The directory is created automatically if it does not exist.

The validation logic resides in [`iroh/src/test_utils/qlog.rs`](https://github.com/n0-computer/iroh/blob/main/iroh/src/test_utils/qlog.rs). The `QlogFileGroup::create` method checks `IROH_TEST_QLOG` at lines 62‑84, while the internal factory reads `QLOGDIR` to determine the output path.

## Implement Qlog in Your Code

### Create a QlogFileGroup

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) manages trace file creation and naming conventions. Instantiate it programmatically or from environment variables:

```rust
use iroh::test_utils::QlogFileGroup;

// Explicit path and prefix
let qlog = QlogFileGroup::new("./qlog", "my_connection");

// Or read from QLOGDIR environment variable
let qlog = QlogFileGroup::from_env("my_connection");

```

### Configure the Transport

Inject the Qlog configuration into your `QuicTransportConfig` using three builder methods available in [`iroh/src/endpoint/quic.rs`](https://github.com/n0-computer/iroh/blob/main/iroh/src/endpoint/quic.rs) (lines 549‑579):

- **`qlog_factory(factory)`** – Supply a custom `QlogFactory` implementation.
- **`qlog_from_env(prefix)`** – Auto-configures using the `QLOGDIR` environment variable.
- **`qlog_from_path(path, prefix)`** – Writes traces to a specific directory.

The `transfer` example in [`iroh/examples/transfer.rs`](https://github.com/n0-computer/iroh/blob/main/iroh/examples/transfer.rs) demonstrates typical usage:

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

let transport = QuicTransportConfig::builder()
    .qlog_from_env("transfer")
    .build();

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

```

## Generate and Analyze Traces

Run your application with the required environment variables:

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

```

This produces timestamped JSON files such as `/tmp/iroh_qlog/transfer.client-2023-05-01-12-00-00.qlog`. Each file follows the [Qlog specification](https://github.com/quiclog/qlog) and contains arrays of events including:

- **Handshake stages** – Look for `client_handshake_start` and `server_handshake_complete` to identify NAT-traversal delays.
- **Path migrations** – Events like `path_created` and `path_removed` reveal multipath activity or dropped routes.
- **Loss and congestion** – `packet_lost` and `congestion_event` entries indicate bandwidth or buffer misconfigurations.
- **Transport parameters** – The initial `transport_parameters` block shows negotiated settings like `max_idle_timeout` and `max_concurrent_multipath_paths`.

Analyze these files using the [Qlog viewer](https://github.com/quiclog/qlog-viewer) or `cattrace` to visualize the connection lifecycle.

## Code Examples

### Minimal Qlog-Enabled Client

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

fn main() -> Result<(), Box<dyn Error>> {
    // Initialize Qlog group writing to ./qlog
    let qlog = QlogFileGroup::new("./qlog", "demo");
    
    // Create transport configuration with Qlog enabled
    let transport = qlog.create("client")?;
    
    // Build and bind endpoint
    let endpoint = Endpoint::builder()
        .transport_config(transport)
        .bind()?;
    
    // Connection will now generate trace files
    let _conn = endpoint.connect("iroh://example.com:443".parse()?)?;
    println!("Connection traced to ./qlog");
    Ok(())
}

```

This pattern—`QlogFileGroup::new` → `create("client")` → `Endpoint::builder().transport_config(...)`—is the standard approach for capturing client-side traces.

### Environment-Based Configuration (No Code Changes)

For existing applications that already call `qlog_from_env`, simply set variables before running:

```bash
export IROH_TEST_QLOG=1
export QLOGDIR=./my_qlog
cargo run --features qlog --bin my_app

```

The application automatically picks up the configuration via `qlog_from_env` as implemented in [`iroh/src/endpoint/quic.rs`](https://github.com/n0-computer/iroh/blob/main/iroh/src/endpoint/quic.rs).

### Custom Qlog Factory (Advanced)

For custom trace handling, implement the `QlogFactory` trait:

```rust
use std::sync::Arc;
use iroh::endpoint::{QuicTransportConfig, QlogFactory};

fn custom_factory() -> Arc<dyn QlogFactory> {
    // Example: Upload traces to S3 or filter specific events
    Arc::new(my_qlog::MyQlogFactory::new())
}

let cfg = QuicTransportConfig::builder()
    .qlog_factory(custom_factory())
    .build();

```

## Summary

- **Enable the feature**: Add `qlog` to your `iroh` dependencies in [`Cargo.toml`](https://github.com/n0-computer/iroh/blob/main/Cargo.toml) to compile tracing support.
- **Set environment variables**: Export `IROH_TEST_QLOG=1` and `QLOGDIR` before running your application to activate file generation.
- **Use QlogFileGroup**: Instantiate this helper from [`iroh/src/test_utils/qlog.rs`](https://github.com/n0-computer/iroh/blob/main/iroh/src/test_utils/qlog.rs) to manage trace file creation and naming conventions.
- **Configure the transport**: Apply `qlog_from_env`, `qlog_from_path`, or `qlog_factory` methods in [`iroh/src/endpoint/quic.rs`](https://github.com/n0-computer/iroh/blob/main/iroh/src/endpoint/quic.rs) to embed tracing into `QuicTransportConfig`.
- **Analyze traces**: Examine generated JSON files for handshake stages, path migrations, and congestion events to identify connection failures.

## Frequently Asked Questions

### What file format does iroh use for Qlog traces?

iroh generates standard **Qlog** files containing JSON arrays of QUIC protocol events. These follow the [Qlog specification](https://github.com/quiclog/qlog) and can be viewed with compatible tools like the Qlog viewer or `cattrace`. Each file includes timestamps, packet numbers, and transport parameters exchanged during the connection lifecycle.

### Why are no Qlog files being generated despite enabling the feature?

First, verify that `IROH_TEST_QLOG=1` is set in your environment, as the `QlogFileGroup::create` method (in [`iroh/src/test_utils/qlog.rs`](https://github.com/n0-computer/iroh/blob/main/iroh/src/test_utils/qlog.rs), lines 62‑84) explicitly checks this variable before creating writers. Second, confirm that `QLOGDIR` points to a valid path with write permissions. Finally, ensure your code actually uses a `QlogFileGroup` or calls `qlog_from_env`/`qlog_from_path` when building the `QuicTransportConfig`; simply enabling the feature does not automatically trace all connections.

### Can I use Qlog tracing in production environments?

While technically possible by enabling the feature and setting the environment variables, Qlog tracing generates significant I/O overhead by writing detailed JSON event streams to disk. The implementation in [`iroh/src/endpoint/quic.rs`](https://github.com/n0-computer/iroh/blob/main/iroh/src/endpoint/quic.rs) is designed for debugging and testing scenarios. For production use, consider implementing a custom `QlogFactory` that filters events or streams to remote aggregation services rather than local files.

### How do I interpret path migration events in the Qlog output?

Look for `path_created` and `path_removed` entries in the trace file. According to the iroh implementation, these events fire when the QUIC stack establishes or tears down network paths during multipath operation. If you see rapid successions of `path_created` followed immediately by `path_removed`, this indicates unstable network conditions or NAT rebinding issues that may cause connection stalls.