Skip to main content

canic_core/ops/runtime/metrics/
lifecycle.rs

1use std::{cell::RefCell, collections::HashMap};
2
3thread_local! {
4    static LIFECYCLE_METRICS: RefCell<HashMap<LifecycleMetricKey, u64>> =
5        RefCell::new(HashMap::new());
6}
7
8///
9/// LifecycleMetricPhase
10///
11
12#[derive(Clone, Copy, Eq, Hash, Ord, PartialEq, PartialOrd)]
13#[remain::sorted]
14pub enum LifecycleMetricPhase {
15    Init,
16    PostUpgrade,
17}
18
19impl LifecycleMetricPhase {
20    #[must_use]
21    pub const fn metric_label(self) -> &'static str {
22        match self {
23            Self::Init => "init",
24            Self::PostUpgrade => "post_upgrade",
25        }
26    }
27}
28
29///
30/// LifecycleMetricRole
31///
32
33#[derive(Clone, Copy, Eq, Hash, Ord, PartialEq, PartialOrd)]
34#[remain::sorted]
35pub enum LifecycleMetricRole {
36    Nonroot,
37    Root,
38}
39
40impl LifecycleMetricRole {
41    #[must_use]
42    pub const fn metric_label(self) -> &'static str {
43        match self {
44            Self::Nonroot => "nonroot",
45            Self::Root => "root",
46        }
47    }
48}
49
50///
51/// LifecycleMetricStage
52///
53
54#[derive(Clone, Copy, Eq, Hash, Ord, PartialEq, PartialOrd)]
55#[remain::sorted]
56pub enum LifecycleMetricStage {
57    Bootstrap,
58    Runtime,
59}
60
61impl LifecycleMetricStage {
62    #[must_use]
63    pub const fn metric_label(self) -> &'static str {
64        match self {
65            Self::Bootstrap => "bootstrap",
66            Self::Runtime => "runtime",
67        }
68    }
69}
70
71///
72/// LifecycleMetricOutcome
73///
74
75#[derive(Clone, Copy, Eq, Hash, Ord, PartialEq, PartialOrd)]
76#[remain::sorted]
77pub enum LifecycleMetricOutcome {
78    Completed,
79    Failed,
80    Scheduled,
81    Skipped,
82    Started,
83    Waiting,
84}
85
86impl LifecycleMetricOutcome {
87    #[must_use]
88    pub const fn metric_label(self) -> &'static str {
89        match self {
90            Self::Completed => "completed",
91            Self::Failed => "failed",
92            Self::Scheduled => "scheduled",
93            Self::Skipped => "skipped",
94            Self::Started => "started",
95            Self::Waiting => "waiting",
96        }
97    }
98}
99
100///
101/// LifecycleMetricKey
102///
103
104#[derive(Clone, Copy, Eq, Hash, PartialEq)]
105pub struct LifecycleMetricKey {
106    pub phase: LifecycleMetricPhase,
107    pub role: LifecycleMetricRole,
108    pub stage: LifecycleMetricStage,
109    pub outcome: LifecycleMetricOutcome,
110}
111
112///
113/// LifecycleMetrics
114///
115
116pub struct LifecycleMetrics;
117
118impl LifecycleMetrics {
119    /// Record one lifecycle stage event.
120    pub fn record(
121        phase: LifecycleMetricPhase,
122        role: LifecycleMetricRole,
123        stage: LifecycleMetricStage,
124        outcome: LifecycleMetricOutcome,
125    ) {
126        LIFECYCLE_METRICS.with_borrow_mut(|counts| {
127            let key = LifecycleMetricKey {
128                phase,
129                role,
130                stage,
131                outcome,
132            };
133            let entry = counts.entry(key).or_insert(0);
134            *entry = entry.saturating_add(1);
135        });
136    }
137
138    /// Snapshot the current lifecycle metric table as stable rows.
139    #[must_use]
140    pub fn snapshot() -> Vec<(LifecycleMetricKey, u64)> {
141        LIFECYCLE_METRICS
142            .with_borrow(std::clone::Clone::clone)
143            .into_iter()
144            .collect()
145    }
146
147    /// Test-only helper: clear all lifecycle metrics.
148    #[cfg(test)]
149    pub fn reset() {
150        LIFECYCLE_METRICS.with_borrow_mut(HashMap::clear);
151    }
152}