Skip to main content

KeyedTrackers

Struct KeyedTrackers 

Source
pub struct KeyedTrackers<K, T: DeltaTracker> { /* private fields */ }
Expand description

A keyed set of delta trackers with a hard bound on its size.

§Per-cycle usage

A collector observes every key the OS still reports, then drops the rest:

use core::time::Duration;
use std::time::Instant;

use monitrs_core::rates::{CounterWidth, KeyedRateTrackers};

let mut rx: KeyedRateTrackers<String> = KeyedRateTrackers::new(CounterWidth::Bits64);
let t0 = Instant::now();

// First cycle: two interfaces, both warming up.
assert!(rx.observe("eth0".to_owned(), 1_000, t0).is_warming_up());
assert!(rx.observe("wlan0".to_owned(), 500, t0).is_warming_up());

// Second cycle: wlan0 is gone, so it is dropped rather than left to accrue.
let t1 = t0 + Duration::from_secs(1);
let eth0 = rx.observe("eth0".to_owned(), 3_000, t1);
rx.retain(|name| name == "eth0");

assert_eq!(eth0.fresh().map(|rate| rate.per_second()), Some(2_000.0));
assert_eq!(rx.len(), 1);

// wlan0 comes back with a counter that restarted: it re-baselines instead of
// reporting the whole counter as one second of traffic.
let t2 = t1 + Duration::from_secs(1);
assert!(rx.observe("wlan0".to_owned(), 90_000, t2).is_warming_up());

Implementations§

Source§

impl<K, T> KeyedTrackers<K, T>
where K: Clone + Eq + Hash, T: DeltaTracker,

Source

pub fn new(config: T::Config) -> Self

Builds an empty set with DEFAULT_MAX_TRACKED and no gap guard.

Source

pub fn with_max_tracked(self, max_tracked: usize) -> Self

Overrides the hard size cap (§10.3).

A cap of zero tracks nothing and reports every key as skipped, which is a branch-free way to disable an expensive metric under load (§16.2).

Source

pub fn with_max_gap(self, max_gap: Duration) -> Self

Treats a gap longer than max_gap between two readings of one key as the key having disappeared and come back (§8.2).

This is a safety net, not the primary mechanism: a collector that calls KeyedTrackers::retain or KeyedTrackers::forget each cycle never needs it. Set it to a small multiple of the sampling interval so ordinary jitter does not trip it, and remember that suspend/resume looks exactly like a disappearance from in here — reporting it as one is the honest answer, because the counter advanced during a period this sample cannot account for.

Source

pub fn observe( &mut self, key: K, reading: T::Reading, at: Instant, ) -> MetricState<T::Value>

Folds one reading for key in and publishes the result.

A key seen for the first time warms up rather than reporting zero (§8.2). at must be monotonic.

Source

pub fn forget(&mut self, key: &K) -> bool

Drops key entirely, so a later re-appearance re-baselines.

This is the explicit answer to every identity change §8.2 lists: a device that vanished, a renamed interface, an exited PID. Returns whether the key was being tracked. The caller publishes the matching UnavailableReasonDeviceDisappeared, InterfaceRenamed, or ProcessExited — for the sample in which it noticed.

Source

pub fn retain(&mut self, keep: impl FnMut(&K) -> bool) -> usize

Keeps only the keys keep accepts, returning how many were dropped.

The cheap per-cycle way to stay bounded: call it with the set of keys the OS still reports. Deliberately not counted as an eviction, because it is the caller acting on knowledge rather than the set defending its budget.

Source

pub fn prune_idle(&mut self, now: Instant, max_idle: Duration) -> usize

Drops trackers that have not seen a reading within max_idle.

The backstop for PID churn: a process that exits is never observed again, so it ages out even if the collector never says it is gone (§10.3). A tracker that never completed a reading holds no baseline worth keeping and is dropped too.

Source

pub fn clear(&mut self)

Drops every tracker.

Source

pub fn len(&self) -> usize

How many keys are currently tracked.

Source

pub fn is_empty(&self) -> bool

Whether nothing is currently tracked.

Source

pub fn contains_key(&self, key: &K) -> bool

Whether key currently has a tracker.

Source

pub fn tracker(&self, key: &K) -> Option<&T>

The tracker for key, for callers that need its raw baseline.

Source

pub const fn max_tracked(&self) -> usize

The hard size cap this set enforces.

Source

pub const fn evictions(&self) -> u64

How many trackers this set has dropped to stay inside its budget.

Worth surfacing through crate::model::CollectorHealth: a non-zero and rising count means the cap is too low for the workload, and rates for the churning keys are being restarted rather than measured.

Trait Implementations§

Source§

impl<K: Debug, T: Debug + DeltaTracker> Debug for KeyedTrackers<K, T>
where T::Config: Debug,

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl<K, T> Default for KeyedTrackers<K, T>
where K: Clone + Eq + Hash, T: DeltaTracker, T::Config: Default,

Source§

fn default() -> Self

Returns the “default value” for a type. Read more

Auto Trait Implementations§

§

impl<K, T> Freeze for KeyedTrackers<K, T>
where <T as DeltaTracker>::Config: Freeze,

§

impl<K, T> RefUnwindSafe for KeyedTrackers<K, T>

§

impl<K, T> Send for KeyedTrackers<K, T>
where <T as DeltaTracker>::Config: Send, K: Send, T: Send,

§

impl<K, T> Sync for KeyedTrackers<K, T>
where <T as DeltaTracker>::Config: Sync, K: Sync, T: Sync,

§

impl<K, T> Unpin for KeyedTrackers<K, T>
where <T as DeltaTracker>::Config: Unpin, K: Unpin, T: Unpin,

§

impl<K, T> UnsafeUnpin for KeyedTrackers<K, T>

§

impl<K, T> UnwindSafe for KeyedTrackers<K, T>

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.