use std::sync::OnceLock;
static RECORDER: OnceLock<Box<dyn MetricsRecorder>> = OnceLock::new();
pub trait MetricsRecorder: Send + Sync + 'static {
fn counter(&self, _name: &str, _value: u64) {}
fn histogram(&self, _name: &str, _value: f64) {}
}
pub fn register(recorder: Box<dyn MetricsRecorder>) -> Result<(), Box<dyn MetricsRecorder>> {
RECORDER.set(recorder)
}
pub mod names {
pub const SESSIONS_STARTED: &str = "ssm_sessions_started_total";
pub const SESSIONS_ENDED: &str = "ssm_sessions_ended_total";
pub const MESSAGES_SENT: &str = "ssm_messages_sent_total";
pub const MESSAGES_RECEIVED: &str = "ssm_messages_received_total";
pub const BYTES_SENT: &str = "ssm_bytes_sent_total";
pub const BYTES_RECEIVED: &str = "ssm_bytes_received_total";
pub const RETRANSMISSIONS: &str = "ssm_retransmissions_total";
pub const ACKS_RECEIVED: &str = "ssm_acks_received_total";
pub const RTT_SECONDS: &str = "ssm_rtt_seconds";
pub const HANDSHAKE_SECONDS: &str = "ssm_handshake_seconds";
}
#[inline]
pub(crate) fn counter(name: &str, value: u64) {
if let Some(recorder) = RECORDER.get() {
recorder.counter(name, value);
}
}
#[inline]
pub(crate) fn histogram(name: &str, value: f64) {
if let Some(recorder) = RECORDER.get() {
recorder.histogram(name, value);
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn recording_without_a_registered_recorder_is_a_no_op() {
counter(names::MESSAGES_SENT, 1);
histogram(names::RTT_SECONDS, 0.01);
}
#[test]
fn metric_names_follow_prometheus_conventions() {
for name in [
names::SESSIONS_STARTED,
names::SESSIONS_ENDED,
names::MESSAGES_SENT,
names::MESSAGES_RECEIVED,
names::BYTES_SENT,
names::BYTES_RECEIVED,
names::RETRANSMISSIONS,
names::ACKS_RECEIVED,
] {
assert!(name.starts_with("ssm_"), "{name}");
assert!(name.ends_with("_total"), "{name}");
}
for name in [names::RTT_SECONDS, names::HANDSHAKE_SECONDS] {
assert!(name.ends_with("_seconds"), "{name}");
}
}
#[test]
fn registration_is_one_shot() {
struct Noop;
impl MetricsRecorder for Noop {}
let _ = register(Box::new(Noop));
assert!(
register(Box::new(Noop)).is_err(),
"a second recorder must be refused"
);
}
}