Reading a node’s :stats (Rust)

A monitor reads a node’s counters with one READ per seam: READ <any vertex>:stats.graph.delivery answers one SETTINGS block of NAME/u64 pairs (RFC-0010 Amendment 1). The example builds the request, then decodes the block a fresh node answers.

What to notice

  • One READ is one seam is one block. The four counters arrive together, sampled in one call, so a monitor compares two whole blocks rather than counters read at different moments.

  • Look counters up by NAME. A reader ignores names it does not know. settings_get returns None for one, which is how a newer node’s extra counters stay harmless.

  • The answer here is built, not received. The crate has no transport, so the example constructs the 113-byte block a fresh node sends. The settings/stats-seam-block conformance vector pins those bytes.

Source

 1// SPDX-License-Identifier: Apache-2.0
 2// SPDX-FileCopyrightText: Copyright 2026 avatarsd LLC
 3
 4/*!
 5 * @brief One concept: reading a node's `:stats` counters. One READ names one seam and
 6 * answers one SETTINGS block of `NAME`/u64 pairs (RFC-0010 Amendment 1).
 7 *
 8 * Run: `cargo run --example fwd_read_stats` (from `bindings/rust/`).
 9 */
10
11use libtracer::fwd::{fwd_kind, fwd_op};
12use libtracer::structured::{settings_get, settings_typed, SettingValue};
13use libtracer::{decode_fwd, encode, encode_fwd_bytes, FieldSel, FwdRequest};
14
15fn main() {
16    // READ <any vertex>:stats.graph.delivery — the seam is node-scoped.
17    let mut req = FwdRequest::new(fwd_op::READ, &["sensor", "temp"], &["client"]);
18    req.field = Some(FieldSel::Str(":stats.graph.delivery"));
19    let frame = encode_fwd_bytes(&req).unwrap();
20    println!("READ :stats.graph.delivery ({} bytes)", frame.len());
21
22    // What a fresh node answers: four u64 LE counters, all zero. (Built here so the
23    // example runs without a peer; the `settings/stats-seam-block` vector pins it.)
24    let zero = 0u64.to_le_bytes();
25    let names = ["no_target", "denied", "out_of_memory", "fan_out_truncated"];
26    let pairs: Vec<_> = names
27        .iter()
28        .map(|n| (*n, SettingValue::Value(&zero)))
29        .collect();
30    let block = settings_typed(&pairs).unwrap();
31    assert_eq!(encode(&block).len(), 113);
32
33    let mut reply = FwdRequest::new(fwd_op::REPLY, &["client"], &["sensor", "temp"]);
34    reply.kind = Some(fwd_kind::RESULT);
35    reply.payload = Some(block);
36    let answer = decode_fwd(&encode_fwd_bytes(&reply).unwrap()).unwrap();
37
38    // A reader looks counters up by NAME and ignores any it does not know.
39    let settings = answer.payload.expect("a RESULT carries the block");
40    for name in names {
41        let raw = settings_get(&settings, name)
42            .unwrap()
43            .expect("counter present");
44        let count = u64::from_le_bytes(raw.try_into().expect("fixed-width u64"));
45        println!("{name:>18} = {count}");
46        assert_eq!(count, 0);
47    }
48    assert_eq!(settings_get(&settings, "not_a_counter").unwrap(), None);
49}

Run it from bindings/rust/:

$ cargo run --example fwd_read_stats

See also: protocol TLVs reference, the :stats record.