Skip to main content

canic_core/api/lifecycle/
mod.rs

1pub mod nonroot;
2pub mod root;
3
4pub mod metrics {
5    use crate::{
6        ids::CanisterRole,
7        ops::runtime::metrics::{
8            canister_ops::CanisterOpsMetrics, lifecycle::LifecycleMetrics,
9            wasm_store::WasmStoreMetrics,
10        },
11    };
12
13    pub use crate::domain::metrics::{
14        CanisterOpsMetricOperation, CanisterOpsMetricOutcome, CanisterOpsMetricReason,
15    };
16
17    pub use crate::domain::metrics::{
18        LifecycleMetricOutcome, LifecycleMetricPhase, LifecycleMetricRole, LifecycleMetricStage,
19    };
20
21    pub use crate::domain::metrics::{
22        WasmStoreMetricOperation, WasmStoreMetricOutcome, WasmStoreMetricReason,
23        WasmStoreMetricSource,
24    };
25
26    ///
27    /// CanisterOpsMetricsApi
28    ///
29
30    pub struct CanisterOpsMetricsApi;
31
32    impl CanisterOpsMetricsApi {
33        /// Record one canister operation metric point for a concrete role.
34        pub fn record(
35            operation: CanisterOpsMetricOperation,
36            role: &CanisterRole,
37            outcome: CanisterOpsMetricOutcome,
38            reason: CanisterOpsMetricReason,
39        ) {
40            CanisterOpsMetrics::record(operation, role, outcome, reason);
41        }
42
43        /// Record one canister operation metric point with no role context.
44        pub fn record_unscoped(
45            operation: CanisterOpsMetricOperation,
46            outcome: CanisterOpsMetricOutcome,
47            reason: CanisterOpsMetricReason,
48        ) {
49            CanisterOpsMetrics::record_unscoped(operation, outcome, reason);
50        }
51
52        /// Record one canister operation metric point when role lookup failed.
53        pub fn record_unknown_role(
54            operation: CanisterOpsMetricOperation,
55            outcome: CanisterOpsMetricOutcome,
56            reason: CanisterOpsMetricReason,
57        ) {
58            CanisterOpsMetrics::record_unknown_role(operation, outcome, reason);
59        }
60    }
61
62    ///
63    /// WasmStoreMetricsApi
64    ///
65
66    pub struct WasmStoreMetricsApi;
67
68    impl WasmStoreMetricsApi {
69        /// Record one wasm-store operation metric point.
70        pub fn record(
71            operation: WasmStoreMetricOperation,
72            source: WasmStoreMetricSource,
73            outcome: WasmStoreMetricOutcome,
74            reason: WasmStoreMetricReason,
75        ) {
76            WasmStoreMetrics::record(operation, source, outcome, reason);
77        }
78    }
79
80    ///
81    /// LifecycleMetricsApi
82    ///
83
84    pub struct LifecycleMetricsApi;
85
86    impl LifecycleMetricsApi {
87        /// Record one lifecycle runtime or bootstrap metric point.
88        pub fn record(
89            phase: LifecycleMetricPhase,
90            role: LifecycleMetricRole,
91            stage: LifecycleMetricStage,
92            outcome: LifecycleMetricOutcome,
93        ) {
94            LifecycleMetrics::record(phase, role, stage, outcome);
95        }
96
97        /// Record one lifecycle runtime metric point.
98        pub fn record_runtime(
99            phase: LifecycleMetricPhase,
100            role: LifecycleMetricRole,
101            outcome: LifecycleMetricOutcome,
102        ) {
103            Self::record(phase, role, LifecycleMetricStage::Runtime, outcome);
104        }
105
106        /// Record one lifecycle bootstrap metric point.
107        pub fn record_bootstrap(
108            phase: LifecycleMetricPhase,
109            role: LifecycleMetricRole,
110            outcome: LifecycleMetricOutcome,
111        ) {
112            Self::record(phase, role, LifecycleMetricStage::Bootstrap, outcome);
113        }
114    }
115
116    #[cfg(test)]
117    mod tests {
118        use super::{
119            CanisterOpsMetricOperation, CanisterOpsMetricOutcome, CanisterOpsMetricReason,
120            CanisterOpsMetricsApi, LifecycleMetricOutcome, LifecycleMetricPhase,
121            LifecycleMetricRole, LifecycleMetricsApi, WasmStoreMetricOperation,
122            WasmStoreMetricOutcome, WasmStoreMetricReason, WasmStoreMetricSource,
123            WasmStoreMetricsApi,
124        };
125        use crate::{
126            domain::metrics::MetricsKind, dto::metrics::MetricValue, ids::CanisterRole,
127            ops::runtime::metrics,
128        };
129
130        // Verify the facade records canister operation metrics with public labels.
131        #[test]
132        fn canister_ops_metrics_api_records_rows() {
133            metrics::reset_for_tests();
134
135            CanisterOpsMetricsApi::record(
136                CanisterOpsMetricOperation::Install,
137                &CanisterRole::new("app"),
138                CanisterOpsMetricOutcome::Failed,
139                CanisterOpsMetricReason::MissingWasm,
140            );
141
142            let entries = metrics::entries(MetricsKind::Core);
143
144            assert_count(
145                &entries,
146                &["canister_ops", "install", "app", "failed", "missing_wasm"],
147                1,
148            );
149        }
150
151        // Verify the facade records wasm-store metrics with public labels.
152        #[test]
153        fn wasm_store_metrics_api_records_rows() {
154            metrics::reset_for_tests();
155
156            WasmStoreMetricsApi::record(
157                WasmStoreMetricOperation::SourceResolve,
158                WasmStoreMetricSource::Store,
159                WasmStoreMetricOutcome::Failed,
160                WasmStoreMetricReason::StoreCall,
161            );
162
163            let entries = metrics::entries(MetricsKind::Storage);
164
165            assert_count(
166                &entries,
167                &[
168                    "wasm_store",
169                    "source_resolve",
170                    "store",
171                    "failed",
172                    "store_call",
173                ],
174                1,
175            );
176        }
177
178        // Verify the facade records both lifecycle metric stages with public labels.
179        #[test]
180        fn lifecycle_metrics_api_records_runtime_and_bootstrap_rows() {
181            metrics::reset_for_tests();
182
183            LifecycleMetricsApi::record_runtime(
184                LifecycleMetricPhase::Init,
185                LifecycleMetricRole::Root,
186                LifecycleMetricOutcome::Completed,
187            );
188            LifecycleMetricsApi::record_bootstrap(
189                LifecycleMetricPhase::PostUpgrade,
190                LifecycleMetricRole::Nonroot,
191                LifecycleMetricOutcome::Scheduled,
192            );
193
194            let entries = metrics::entries(MetricsKind::Core);
195
196            assert_count(
197                &entries,
198                &["lifecycle", "init", "root", "runtime", "completed"],
199                1,
200            );
201            assert_count(
202                &entries,
203                &[
204                    "lifecycle",
205                    "post_upgrade",
206                    "nonroot",
207                    "bootstrap",
208                    "scheduled",
209                ],
210                1,
211            );
212        }
213
214        // Assert one metric row count by its stable public labels.
215        fn assert_count(entries: &[crate::dto::metrics::MetricEntry], labels: &[&str], count: u64) {
216            let entry = entries
217                .iter()
218                .find(|entry| {
219                    entry
220                        .labels
221                        .iter()
222                        .map(String::as_str)
223                        .eq(labels.iter().copied())
224                })
225                .expect("metric entry should exist");
226
227            std::assert_matches!(
228                &entry.value,
229                MetricValue::Count(actual) if *actual == count
230            );
231        }
232    }
233}