iroh Metrics for Monitoring Endpoint and Connection Health: Complete Reference

iroh exposes a comprehensive telemetry system through iroh_metrics::Counter objects defined in 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, 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:

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, which demonstrates periodic metric logging suitable for adaptation to Prometheus exporters.

Summary

  • Location: All counters are defined in iroh/src/socket/metrics.rs and exposed via EndpointMetrics in 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 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 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.

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 →