canic_core/model/metrics/
system.rs1use candid::CandidType;
2use serde::{Deserialize, Serialize};
3use std::{cell::RefCell, collections::HashMap};
4
5thread_local! {
6 static SYSTEM_METRICS: RefCell<HashMap<SystemMetricKind, u64>> = RefCell::new(HashMap::new());
7}
8
9#[derive(
15 CandidType, Clone, Copy, Debug, Deserialize, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize,
16)]
17#[remain::sorted]
18pub enum SystemMetricKind {
19 CanisterCall,
20 CanisterStatus,
21 CreateCanister,
22 DeleteCanister,
23 DepositCycles,
24 HttpOutcall,
25 InstallCode,
26 ReinstallCode,
27 TimerScheduled,
28 UninstallCode,
29 UpdateSettings,
30 UpgradeCode,
31}
32
33#[derive(CandidType, Clone, Debug, Deserialize, Serialize)]
39pub struct SystemMetricEntry {
40 pub kind: SystemMetricKind,
41 pub count: u64,
42}
43
44pub type SystemMetricsSnapshot = Vec<SystemMetricEntry>;
49
50pub struct SystemMetrics;
56
57impl SystemMetrics {
58 pub fn increment(kind: SystemMetricKind) {
60 SYSTEM_METRICS.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<SystemMetricEntry> {
69 SYSTEM_METRICS.with_borrow(|counts| {
70 counts
71 .iter()
72 .map(|(kind, count)| SystemMetricEntry {
73 kind: *kind,
74 count: *count,
75 })
76 .collect()
77 })
78 }
79
80 #[cfg(test)]
81 pub fn reset() {
82 SYSTEM_METRICS.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 system_metrics_increments_and_snapshots() {
97 SystemMetrics::reset();
98
99 SystemMetrics::increment(SystemMetricKind::CreateCanister);
100 SystemMetrics::increment(SystemMetricKind::CreateCanister);
101 SystemMetrics::increment(SystemMetricKind::InstallCode);
102
103 let snapshot = SystemMetrics::snapshot();
104 let as_map: HashMap<SystemMetricKind, u64> = snapshot
105 .into_iter()
106 .map(|entry| (entry.kind, entry.count))
107 .collect();
108
109 assert_eq!(as_map.get(&SystemMetricKind::CreateCanister), Some(&2));
110 assert_eq!(as_map.get(&SystemMetricKind::InstallCode), Some(&1));
111 assert!(!as_map.contains_key(&SystemMetricKind::CanisterCall));
112 }
113}