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::ops::runtime::metrics::canister_ops::{
14        CanisterOpsMetricOperation, CanisterOpsMetricOutcome, CanisterOpsMetricReason,
15    };
16
17    pub use crate::ops::runtime::metrics::lifecycle::{
18        LifecycleMetricOutcome, LifecycleMetricPhase, LifecycleMetricRole, LifecycleMetricStage,
19    };
20
21    pub use crate::ops::runtime::metrics::wasm_store::{
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            dto::metrics::{MetricValue, MetricsKind},
127            ids::CanisterRole,
128            ops::runtime::metrics,
129        };
130
131        // Verify the facade records canister operation metrics with public labels.
132        #[test]
133        fn canister_ops_metrics_api_records_rows() {
134            metrics::reset_for_tests();
135
136            CanisterOpsMetricsApi::record(
137                CanisterOpsMetricOperation::Install,
138                &CanisterRole::new("app"),
139                CanisterOpsMetricOutcome::Failed,
140                CanisterOpsMetricReason::MissingWasm,
141            );
142
143            let entries = metrics::entries(MetricsKind::Core);
144
145            assert_count(
146                &entries,
147                &["canister_ops", "install", "app", "failed", "missing_wasm"],
148                1,
149            );
150        }
151
152        // Verify the facade records wasm-store metrics with public labels.
153        #[test]
154        fn wasm_store_metrics_api_records_rows() {
155            metrics::reset_for_tests();
156
157            WasmStoreMetricsApi::record(
158                WasmStoreMetricOperation::SourceResolve,
159                WasmStoreMetricSource::Store,
160                WasmStoreMetricOutcome::Failed,
161                WasmStoreMetricReason::StoreCall,
162            );
163
164            let entries = metrics::entries(MetricsKind::Storage);
165
166            assert_count(
167                &entries,
168                &[
169                    "wasm_store",
170                    "source_resolve",
171                    "store",
172                    "failed",
173                    "store_call",
174                ],
175                1,
176            );
177        }
178
179        // Verify the facade records both lifecycle metric stages with public labels.
180        #[test]
181        fn lifecycle_metrics_api_records_runtime_and_bootstrap_rows() {
182            metrics::reset_for_tests();
183
184            LifecycleMetricsApi::record_runtime(
185                LifecycleMetricPhase::Init,
186                LifecycleMetricRole::Root,
187                LifecycleMetricOutcome::Completed,
188            );
189            LifecycleMetricsApi::record_bootstrap(
190                LifecycleMetricPhase::PostUpgrade,
191                LifecycleMetricRole::Nonroot,
192                LifecycleMetricOutcome::Scheduled,
193            );
194
195            let entries = metrics::entries(MetricsKind::Core);
196
197            assert_count(
198                &entries,
199                &["lifecycle", "init", "root", "runtime", "completed"],
200                1,
201            );
202            assert_count(
203                &entries,
204                &[
205                    "lifecycle",
206                    "post_upgrade",
207                    "nonroot",
208                    "bootstrap",
209                    "scheduled",
210                ],
211                1,
212            );
213        }
214
215        // Assert one metric row count by its stable public labels.
216        fn assert_count(entries: &[crate::dto::metrics::MetricEntry], labels: &[&str], count: u64) {
217            let entry = entries
218                .iter()
219                .find(|entry| {
220                    entry
221                        .labels
222                        .iter()
223                        .map(String::as_str)
224                        .eq(labels.iter().copied())
225                })
226                .expect("metric entry should exist");
227
228            assert!(matches!(&entry.value, MetricValue::Count(actual) if *actual == count));
229        }
230    }
231}