liminal_server/
metrics.rs1use std::sync::OnceLock;
10
11use liminal::metrics::{
12 CounterHandle, GaugeHandle, MetricsRegistry, global_registry, install_global_registry,
13};
14
15const CONNECTIONS_ACTIVE: &str = "liminal_connections_active";
16const PUBLISHES_TOTAL: &str = "liminal_publishes_total";
17const DELIVERIES_TOTAL: &str = "liminal_deliveries_total";
18
19static SERVER_METRICS: OnceLock<ServerMetrics> = OnceLock::new();
20
21#[derive(Clone, Debug)]
23struct ServerMetrics {
24 connections_active: GaugeHandle,
25 publishes_total: CounterHandle,
26 deliveries_total: CounterHandle,
27}
28
29pub fn init() {
35 if SERVER_METRICS.get().is_some() {
36 return;
37 }
38 let Some(registry) = global_or_install() else {
39 return;
40 };
41 if let Some(metrics) = ServerMetrics::register(registry) {
42 let _ = SERVER_METRICS.set(metrics);
43 }
44}
45
46pub fn connection_spawned() {
49 if let Some(metrics) = SERVER_METRICS.get() {
50 metrics.connections_active.increment();
51 }
52}
53
54pub fn connection_closed() {
57 if let Some(metrics) = SERVER_METRICS.get() {
58 metrics.connections_active.decrement();
59 }
60}
61
62pub fn publish_accepted() {
65 if let Some(metrics) = SERVER_METRICS.get() {
66 metrics.publishes_total.increment();
67 }
68}
69
70pub fn deliveries_recorded(count: u64) {
74 if count == 0 {
75 return;
76 }
77 if let Some(metrics) = SERVER_METRICS.get() {
78 metrics.deliveries_total.increment_by(count);
79 }
80}
81
82impl ServerMetrics {
83 fn register(registry: &MetricsRegistry) -> Option<Self> {
84 let connections_active = registry
85 .register_gauge(CONNECTIONS_ACTIVE, no_labels())
86 .ok()?;
87 let publishes_total = registry
88 .register_counter(PUBLISHES_TOTAL, no_labels())
89 .ok()?;
90 let deliveries_total = registry
91 .register_counter(DELIVERIES_TOTAL, no_labels())
92 .ok()?;
93 Some(Self {
94 connections_active,
95 publishes_total,
96 deliveries_total,
97 })
98 }
99}
100
101const fn no_labels() -> std::iter::Empty<(&'static str, &'static str)> {
102 std::iter::empty()
103}
104
105fn global_or_install() -> Option<&'static MetricsRegistry> {
110 if let Some(registry) = global_registry() {
111 return Some(registry);
112 }
113 let _ = install_global_registry(MetricsRegistry::new());
116 global_registry()
117}
118
119#[cfg(test)]
120mod tests {
121 use super::{
122 CONNECTIONS_ACTIVE, DELIVERIES_TOTAL, PUBLISHES_TOTAL, connection_spawned,
123 deliveries_recorded, init, publish_accepted,
124 };
125 use liminal::metrics::{global_registry, render};
126
127 #[test]
128 fn init_registers_the_three_server_families_on_the_global_registry()
129 -> Result<(), Box<dyn std::error::Error>> {
130 init();
131 connection_spawned();
132 publish_accepted();
133 deliveries_recorded(2);
134
135 let registry =
136 global_registry().ok_or("init must install and enable the global registry")?;
137 let exposition = render(®istry.snapshot());
138
139 assert!(exposition.contains(CONNECTIONS_ACTIVE));
140 assert!(exposition.contains(PUBLISHES_TOTAL));
141 assert!(exposition.contains(DELIVERIES_TOTAL));
142
143 Ok(())
144 }
145}