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::CanisterOps);
144
145            assert_count(&entries, &["install", "app", "failed", "missing_wasm"], 1);
146        }
147
148        // Verify the facade records wasm-store metrics with public labels.
149        #[test]
150        fn wasm_store_metrics_api_records_rows() {
151            metrics::reset_for_tests();
152
153            WasmStoreMetricsApi::record(
154                WasmStoreMetricOperation::SourceResolve,
155                WasmStoreMetricSource::Store,
156                WasmStoreMetricOutcome::Failed,
157                WasmStoreMetricReason::StoreCall,
158            );
159
160            let entries = metrics::entries(MetricsKind::WasmStore);
161
162            assert_count(
163                &entries,
164                &["source_resolve", "store", "failed", "store_call"],
165                1,
166            );
167        }
168
169        // Verify the facade records both lifecycle metric stages with public labels.
170        #[test]
171        fn lifecycle_metrics_api_records_runtime_and_bootstrap_rows() {
172            metrics::reset_for_tests();
173
174            LifecycleMetricsApi::record_runtime(
175                LifecycleMetricPhase::Init,
176                LifecycleMetricRole::Root,
177                LifecycleMetricOutcome::Completed,
178            );
179            LifecycleMetricsApi::record_bootstrap(
180                LifecycleMetricPhase::PostUpgrade,
181                LifecycleMetricRole::Nonroot,
182                LifecycleMetricOutcome::Scheduled,
183            );
184
185            let entries = metrics::entries(MetricsKind::Lifecycle);
186
187            assert_count(&entries, &["init", "root", "runtime", "completed"], 1);
188            assert_count(
189                &entries,
190                &["post_upgrade", "nonroot", "bootstrap", "scheduled"],
191                1,
192            );
193        }
194
195        // Assert one metric row count by its stable public labels.
196        fn assert_count(entries: &[crate::dto::metrics::MetricEntry], labels: &[&str], count: u64) {
197            let entry = entries
198                .iter()
199                .find(|entry| {
200                    entry
201                        .labels
202                        .iter()
203                        .map(String::as_str)
204                        .eq(labels.iter().copied())
205                })
206                .expect("metric entry should exist");
207
208            assert!(matches!(&entry.value, MetricValue::Count(actual) if *actual == count));
209        }
210    }
211}