canic_core/model/
metrics.rs1use candid::CandidType;
2use serde::{Deserialize, Serialize};
3use std::{cell::RefCell, collections::HashMap};
4
5thread_local! {
6 static METRIC_COUNTS: RefCell<HashMap<MetricKind, u64>> = RefCell::new(HashMap::new());
7}
8
9pub type MetricsSnapshot = Vec<MetricEntry>;
18
19#[derive(CandidType, Clone, Copy, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
24pub enum MetricKind {
25 CreateCanister,
26 InstallCode,
27 ReinstallCode,
28 UpgradeCode,
29 UninstallCode,
30 DeleteCanister,
31 DepositCycles,
32 CanisterStatus,
33 CanisterCall,
34}
35
36#[derive(CandidType, Clone, Debug, Deserialize, Serialize)]
42pub struct MetricEntry {
43 pub kind: MetricKind,
44 pub count: u64,
45}
46
47pub struct MetricsState;
56
57impl MetricsState {
58 pub fn increment(kind: MetricKind) {
60 METRIC_COUNTS.with_borrow_mut(|counts| {
61 let entry = counts.entry(kind).or_insert(0);
62 *entry = entry.saturating_add(1);
63 });
64 }
65
66 #[must_use]
68 pub fn snapshot() -> Vec<MetricEntry> {
69 METRIC_COUNTS.with_borrow(|counts| {
70 counts
71 .iter()
72 .map(|(kind, count)| MetricEntry {
73 kind: *kind,
74 count: *count,
75 })
76 .collect()
77 })
78 }
79
80 #[cfg(test)]
81 pub fn reset() {
82 METRIC_COUNTS.with_borrow_mut(HashMap::clear);
83 }
84}
85
86#[cfg(test)]
91mod tests {
92 use super::*;
93 use std::collections::HashMap;
94
95 #[test]
96 fn increments_and_snapshots() {
97 MetricsState::reset();
98
99 MetricsState::increment(MetricKind::CreateCanister);
100 MetricsState::increment(MetricKind::CreateCanister);
101 MetricsState::increment(MetricKind::InstallCode);
102
103 let snapshot = MetricsState::snapshot();
104 let as_map: HashMap<MetricKind, u64> = snapshot
105 .into_iter()
106 .map(|entry| (entry.kind, entry.count))
107 .collect();
108
109 assert_eq!(as_map.get(&MetricKind::CreateCanister), Some(&2));
110 assert_eq!(as_map.get(&MetricKind::InstallCode), Some(&1));
111 assert!(!as_map.contains_key(&MetricKind::CanisterCall));
112 }
113}