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 respectivelyrecv_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 transportrecv_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 receivedrecv_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 openednum_conns_closed: Total handshaked connections closednum_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 peerspaths_relay: Number of relayed network paths to peerspaths_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 lifecycletransport_relay_paths_added/transport_relay_paths_removed: Relay path lifecycletransport_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 loopactor_tick_msg: Messages processed by the socket actoractor_tick_re_stun: Periodic re-STUN timer ticks handled (NAT refreshes)actor_tick_portmap_changed: Port-mapping change events processedactor_link_change: Local network interface change eventsactor_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.rsand exposed viaEndpointMetricsiniroh/src/socket.rs - Type: All metrics are
iroh_metrics::Counterobjects readable via theget()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 aMetricsGroupSetcontaining the socket metrics struct - Health Indicators: Monitor
num_conns_directvspaths_relay,holepunch_attempts, andrelay_home_changefor 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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →