Skip to main content

Module throttle

Module throttle 

Source
Expand description

phase-417 W4.d — rate-limited logging, on the Logger everything else uses.

§Why this lives here and not in nros-core

Before this module there WAS a throttle in the tree — nros_core::logger::Logger::{debug,info,warn,error,trace}_throttle — on a DIFFERENT Logger type: one that forwards to the log crate and therefore never reaches nros_platform_log_write. So the capability existed on the logger nothing dispatches through, and was missing from the logger everything dispatches through. RFC-0019 makes the Rust API the source of truth for C and C++, and the type the FFI hands out is crate::Logger — so the throttle has to be here for the wrappers to be thin.

§The decision function is shared, deliberately

Two storages need this rule: a 'static ThrottleState (what the Rust macros declare at the call site) and a caller-owned uint64_t (what the C macros declare, because a C call site cannot name a Rust type without a hand-mirrored struct — the drift class issue 0160 catalogues). Both call throttle_decide. RFC-0089: a second spelling is free, a second code path that can produce a different answer is not.

§Contract

  • The FIRST record at a call site always emits. rclcpp’s RCLCPP_*_THROTTLE does the same; nros_core’s old should_log_throttled did NOT (it started from last = 0 and compared now >= last + interval, so at now < interval the first message was dropped).
  • The window is measured from the last EMITTED record, not from the last attempt.
  • The severity threshold is checked BEFORE the window, so a record filtered by crate::Logger::level does not consume the window.
  • A clock that does not move is a window that never elapses: a site whose clock is stuck (at ANY value, 0 included) emits once and then never (issue 1152). A clock that wraps still measures real elapsed time across the wrap. Both are tested below.

Structs§

ThrottleState
Per-call-site throttle window.

Functions§

interval_ms_to_ns
Milliseconds to nanoseconds, saturating.
throttle_decide
The whole rule, as a pure function. Both storages call this.