# iroh Metrics for Monitoring Endpoint and Connection Health: Complete Reference

> Discover iroh metrics for endpoint and connection health. Monitor data transfers, connection lifecycles, path quality, NAT traversal, and actor loop health with real time visibility.

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

---

**iroh exposes a comprehensive telemetry system through `iroh_metrics::Counter` objects defined in [`iroh/src/socket/metrics.rs`](https://github.com/n0-computer/iroh/blob/main/iroh/src/socket/metrics.rs), accessible via the `Endpoint::metrics()` method, providing real-time visibility into data transfer volumes, connection lifecycles, path quality, NAT traversal attempts, and actor loop health.**

The `n0-computer/iroh` repository ships with a built-in metrics subsystem that enables operators to monitor endpoint and connection health without external instrumentation. By querying the `Metrics` struct exposed through the `EndpointMetrics` wrapper in [`iroh/src/socket.rs`](https://github.com/n0-computer/iroh/blob/main/iroh/src/socket.rs), you can track bandwidth utilization, relay dependencies, and connection stability for debugging production issues.

## Socket-Level Metrics Architecture

All telemetry counters are defined as **`iroh_metrics::Counter`** objects within the `Metrics` group. You can read current values using the `get()` method (e.g., `metrics.send_ipv4.get()`), which returns a `u64` representing the cumulative count since endpoint initialization.

The endpoint aggregates a **`MetricsGroupSet`** containing both socket-level metrics and per-endpoint statistics, making it straightforward to export snapshots via tracing events or Prometheus exporters.

## Data Transfer and Network Traffic Metrics

### IPv4 and IPv6 Byte Counters

Monitor raw bandwidth usage per IP version using the send and receive counters:

- **`send_ipv4`** / **`send_ipv6`**: Number of bytes sent over IPv4 and IPv6 transports respectively
- **`recv_data_ipv4`** / **`recv_data_ipv6`**: Number of bytes received over IPv4 and IPv6 transports

These counters help identify asymmetric routing or version-specific connectivity issues.

### Relay Traffic Monitoring

Detect reliance on relay nodes versus direct paths:

- **`send_relay`**: Bytes sent over relay transport
- **`recv_data_relay`**: Bytes received from relay transport

High values in these counters may indicate NAT traversal failures forcing traffic through relay nodes.

### Datagram-Level Statistics

For packet-level visibility:

- **`recv_datagrams`**: Total QUIC packets received
- **`recv_gro_datagrams`**: Number of Generic Receive Offload (GRO) batches received

The GRO counter indicates how often the kernel coalesces packets, which affects latency measurements.

## Connection Health Indicators

### Connection Lifecycle Counters

Track handshake completion and churn rates:

- **`num_conns_opened`**: Total handshaked connections opened
- **`num_conns_closed`**: Total handshaked connections closed
- **`num_conns_direct`**: Connections established via direct paths (lower latency)

Monitor the ratio of opened to closed connections to detect connection churn or instability.

### Path Quality Metrics

Assess connectivity quality through path distribution:

- **`paths_direct`**: Number of direct network paths to peers
- **`paths_relay`**: Number of relayed network paths to peers  
- **`paths_custom`**: Number of user-defined custom transport paths

A healthy endpoint maintains high `paths_direct` counts relative to `paths_relay`.

### NAT Traversal Monitoring

Track hole-punching attempts:

- **`holepunch_attempts`**: Times hole-punching was initiated on a connection (client-side only)

Frequent increments without corresponding direct path establishment suggest NAT traversal difficulties.

## Transport Path Lifecycle Tracking

The metrics system tracks additions and removals for three transport categories:

- **`transport_ip_paths_added`** / **`transport_ip_paths_removed`**: Direct IP path lifecycle
- **`transport_relay_paths_added`** / **`transport_relay_paths_removed`**: Relay path lifecycle  
- **`transport_custom_paths_added`** / **`transport_custom_paths_removed`**: Custom transport path lifecycle

These counters help diagnose path instability and flapping connections.

## Relay and Network Stability

Monitor relay infrastructure health:

- **`relay_home_change`**: Times the home relay changed to a different relay (including initial assignment)

Frequent changes indicate relay instability or network topology shifts.

## Actor Loop and System Health Metrics

Track internal event loop activity:

- **`actor_tick_main`**: Iterations of the main socket actor loop
- **`actor_tick_msg`**: Messages processed by the socket actor
- **`actor_tick_re_stun`**: Periodic re-STUN timer ticks handled (NAT refreshes)
- **`actor_tick_portmap_changed`**: Port-mapping change events processed
- **`actor_link_change`**: Local network interface change events
- **`actor_tick_other`**: Miscellaneous actor loop activity

High `actor_tick_msg` values relative to data transfer may indicate excessive control plane load.

## Accessing Metrics Programmatically

Query metrics through the endpoint's `metrics()` method as shown in [`iroh/src/socket.rs`](https://github.com/n0-computer/iroh/blob/main/iroh/src/socket.rs):

```rust
use iroh::Endpoint;

// Create endpoint
let endpoint = Endpoint::builder().bind().await?;

// Obtain metrics reference
let metrics = endpoint.metrics();

// Log key health indicators
println!("IPv4 bytes sent: {}", metrics.socket.send_ipv4.get());
println!("IPv6 bytes sent: {}", metrics.socket.send_ipv6.get());
println!("Relay bytes sent: {}", metrics.socket.send_relay.get());

println!("Connections opened: {}", metrics.socket.num_conns_opened.get());
println!("Connections closed: {}", metrics.socket.num_conns_closed.get());

println!("Holepunch attempts: {}", metrics.socket.holepunch_attempts.get());
println!("Direct paths: {}", metrics.socket.paths_direct.get());
println!("Relay paths: {}", metrics.socket.paths_relay.get());

```

For continuous monitoring, reference [`iroh/examples/monitor-connections.rs`](https://github.com/n0-computer/iroh/blob/main/iroh/examples/monitor-connections.rs), which demonstrates periodic metric logging suitable for adaptation to Prometheus exporters.

## Summary

- **Location**: All counters are defined in [`iroh/src/socket/metrics.rs`](https://github.com/n0-computer/iroh/blob/main/iroh/src/socket/metrics.rs) and exposed via `EndpointMetrics` in [`iroh/src/socket.rs`](https://github.com/n0-computer/iroh/blob/main/iroh/src/socket.rs)
- **Type**: All metrics are `iroh_metrics::Counter` objects readable via the `get()` method
- **Key Categories**: Data transfer (IPv4/IPv6/relay), connection lifecycle, path quality, hole-punching attempts, transport lifecycle, and actor loop health
- **Access Pattern**: Call `endpoint.metrics()` to receive a `MetricsGroupSet` containing the socket metrics struct
- **Health Indicators**: Monitor `num_conns_direct` vs `paths_relay`, `holepunch_attempts`, and `relay_home_change` for connectivity quality

## Frequently Asked Questions

### How do I access iroh metrics programmatically?

Call the `metrics()` method on your `Endpoint` instance to receive an `EndpointMetrics` wrapper containing the `Metrics` struct. Each counter is an `iroh_metrics::Counter` that exposes a `get()` method returning the current `u64` value. The example in [`iroh/examples/monitor-connections.rs`](https://github.com/n0-computer/iroh/blob/main/iroh/examples/monitor-connections.rs) demonstrates polling these values in an async monitoring task.

### Which metrics indicate relay dependency issues?

Monitor **`recv_data_relay`** and **`send_relay`** to detect heavy relay traffic. Compare these against **`recv_data_ipv4`**, **`recv_data_ipv6`**, and **`send_ipv4`**, **`send_ipv6`**. Additionally, track **`paths_relay`** versus **`paths_direct`**—a high relay path count suggests NAT traversal failures forcing connections through relay nodes.

### What counters help diagnose NAT traversal problems?

The **`holepunch_attempts`** counter increments each time the client initiates hole-punching. If this value increases rapidly without a corresponding increase in **`paths_direct`** or **`num_conns_direct`**, it indicates failed NAT traversal attempts. Also monitor **`actor_tick_re_stun`** to ensure periodic STUN refreshes are occurring.

### How can I export iroh metrics to Prometheus?

The `MetricsGroupSet` returned by `endpoint.metrics()` can be iterated to extract all counter values. While iroh does not include a built-in Prometheus exporter, you can adapt the logic in [`iroh/examples/monitor-connections.rs`](https://github.com/n0-computer/iroh/blob/main/iroh/examples/monitor-connections.rs) to format these counters for Prometheus, typically by running a background task that periodically reads `metrics.socket.*.get()` values and exposes them via an HTTP endpoint.