appcore_ops/metrics.rs
1// =============================================================================
2// #######
3// ### ### F: metrics.rs
4// ## ## ## ## P: AppCore-Runtime
5// ## ##
6// C: 2026/06/02 17:10:40 by dnettoRaw
7// ## ## ## ## U: 2026/07/23 23:50:45 by dnettoRaw
8// ########### S: 1.0.1-rc.8
9// =============================================================================
10
11//! Minimal in-memory counters for local runtime diagnostics.
12
13use parking_lot::Mutex;
14use serde::{Deserialize, Serialize};
15use std::collections::BTreeMap;
16
17/// Named monotonic counter snapshot.
18#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
19pub struct MetricCounter {
20 /// Stable metric name.
21 pub name: String,
22 /// Current counter value.
23 pub value: u64,
24}
25
26/// Process-local monotonic counter registry.
27#[derive(Debug, Default)]
28pub struct InMemoryMetrics {
29 counters: Mutex<BTreeMap<String, u64>>,
30}
31
32impl InMemoryMetrics {
33 /// Creates an empty counter registry.
34 pub fn new() -> Self {
35 Self::default()
36 }
37
38 /// Saturating-increments a named counter and returns its new value.
39 pub fn increment(&self, name: &str) -> u64 {
40 let mut counters = self.counters.lock();
41 let value = counters.entry(name.to_string()).or_insert(0);
42 *value = value.saturating_add(1);
43 *value
44 }
45
46 /// Returns counters ordered by name.
47 pub fn snapshot(&self) -> Vec<MetricCounter> {
48 let counters = self.counters.lock();
49 counters
50 .iter()
51 .map(|(name, value)| MetricCounter {
52 name: name.clone(),
53 value: *value,
54 })
55 .collect()
56 }
57}
58
59#[cfg(test)]
60#[path = "metrics_tests.rs"]
61mod tests;