Skip to main content

canic_core/workflow/metrics/
query.rs

1use crate::{
2    dto::{
3        metrics::{
4            AccessMetricEntry, CyclesFundingMetricEntry, DelegationMetricEntry, EndpointHealth,
5            HttpMetricEntry, IccMetricEntry, MetricsKind, MetricsRequest, MetricsResponse,
6            RootCapabilityMetricEntry, SystemMetricEntry, TimerMetricEntry,
7        },
8        page::{Page, PageRequest},
9    },
10    ops::{
11        perf::PerfOps,
12        runtime::metrics::{
13            MetricsOps,
14            mapper::{
15                AccessMetricEntryMapper, CyclesFundingMetricEntryMapper,
16                DelegationMetricEntryMapper, EndpointHealthMapper, HttpMetricEntryMapper,
17                IccMetricEntryMapper, RootCapabilityMetricEntryMapper, SystemMetricEntryMapper,
18                TimerMetricEntryMapper,
19            },
20        },
21    },
22    perf::PerfEntry,
23    workflow::view::paginate::paginate_vec,
24};
25
26///
27/// MetricsQuery
28///
29/// Read-only query façade over metric snapshots.
30/// Responsible for mapping, sorting, and pagination only.
31///
32
33pub struct MetricsQuery;
34
35impl MetricsQuery {
36    #[must_use]
37    pub fn dispatch(req: MetricsRequest) -> MetricsResponse {
38        match req.kind {
39            MetricsKind::System => MetricsResponse::System(Self::system_snapshot()),
40            MetricsKind::Icc => MetricsResponse::Icc(Self::icc_page(req.page)),
41            MetricsKind::Http => MetricsResponse::Http(Self::http_page(req.page)),
42            MetricsKind::Timer => MetricsResponse::Timer(Self::timer_page(req.page)),
43            MetricsKind::Access => MetricsResponse::Access(Self::access_page(req.page)),
44            MetricsKind::Delegation => MetricsResponse::Delegation(Self::delegation_page(req.page)),
45            MetricsKind::RootCapability => {
46                MetricsResponse::RootCapability(Self::root_capability_page(req.page))
47            }
48            MetricsKind::CyclesFunding => {
49                MetricsResponse::CyclesFunding(Self::cycles_funding_page(req.page))
50            }
51            MetricsKind::Perf => MetricsResponse::Perf(Self::perf_page(req.page)),
52            MetricsKind::EndpointHealth => MetricsResponse::EndpointHealth(
53                Self::endpoint_health_page(req.page, Some(crate::protocol::CANIC_METRICS)),
54            ),
55        }
56    }
57
58    #[must_use]
59    pub fn system_snapshot() -> Vec<SystemMetricEntry> {
60        let snapshot = MetricsOps::system_snapshot();
61        let mut entries = SystemMetricEntryMapper::record_to_view(snapshot.entries);
62
63        entries.sort_by(|a, b| a.kind.cmp(&b.kind));
64
65        entries
66    }
67
68    #[must_use]
69    pub fn icc_page(page: PageRequest) -> Page<IccMetricEntry> {
70        let snapshot = MetricsOps::icc_snapshot();
71        let mut entries = IccMetricEntryMapper::record_to_view(snapshot.entries);
72
73        entries.sort_by(|a, b| {
74            a.target
75                .as_slice()
76                .cmp(b.target.as_slice())
77                .then_with(|| a.method.cmp(&b.method))
78        });
79
80        paginate_vec(entries, page)
81    }
82
83    #[must_use]
84    pub fn http_page(page: PageRequest) -> Page<HttpMetricEntry> {
85        let snapshot = MetricsOps::http_snapshot();
86        let mut entries = HttpMetricEntryMapper::record_to_view(snapshot.entries);
87
88        entries.sort_by(|a, b| a.method.cmp(&b.method).then_with(|| a.label.cmp(&b.label)));
89
90        paginate_vec(entries, page)
91    }
92
93    #[must_use]
94    pub fn timer_page(page: PageRequest) -> Page<TimerMetricEntry> {
95        let snapshot = MetricsOps::timer_snapshot();
96        let mut entries = TimerMetricEntryMapper::record_to_view(snapshot.entries);
97
98        entries.sort_by(|a, b| {
99            a.mode
100                .cmp(&b.mode)
101                .then_with(|| a.delay_ms.cmp(&b.delay_ms))
102                .then_with(|| a.label.cmp(&b.label))
103        });
104
105        paginate_vec(entries, page)
106    }
107
108    #[must_use]
109    pub fn access_page(page: PageRequest) -> Page<AccessMetricEntry> {
110        let snapshot = MetricsOps::access_snapshot();
111        let mut entries = AccessMetricEntryMapper::record_to_view(snapshot.entries);
112
113        entries.sort_by(|a, b| {
114            a.endpoint
115                .cmp(&b.endpoint)
116                .then_with(|| a.kind.cmp(&b.kind))
117                .then_with(|| a.predicate.cmp(&b.predicate))
118        });
119
120        paginate_vec(entries, page)
121    }
122
123    #[must_use]
124    pub fn delegation_page(page: PageRequest) -> Page<DelegationMetricEntry> {
125        let snapshot = MetricsOps::delegation_snapshot();
126        let mut entries = DelegationMetricEntryMapper::record_to_view(snapshot.entries);
127
128        entries.sort_by(|a, b| a.authority.as_slice().cmp(b.authority.as_slice()));
129
130        paginate_vec(entries, page)
131    }
132
133    #[must_use]
134    pub fn root_capability_page(page: PageRequest) -> Page<RootCapabilityMetricEntry> {
135        let snapshot = MetricsOps::root_capability_snapshot();
136        let mut entries = RootCapabilityMetricEntryMapper::record_to_view(snapshot.entries);
137
138        entries.sort_by(|a, b| {
139            a.capability
140                .cmp(&b.capability)
141                .then_with(|| a.event_type.cmp(&b.event_type))
142                .then_with(|| a.outcome.cmp(&b.outcome))
143                .then_with(|| a.proof_mode.cmp(&b.proof_mode))
144        });
145
146        paginate_vec(entries, page)
147    }
148
149    #[must_use]
150    pub fn cycles_funding_page(page: PageRequest) -> Page<CyclesFundingMetricEntry> {
151        let snapshot = MetricsOps::cycles_funding_snapshot();
152        let mut entries = CyclesFundingMetricEntryMapper::record_to_view(snapshot.entries);
153
154        entries.sort_by(|a, b| {
155            a.metric
156                .cmp(&b.metric)
157                .then_with(|| a.child_principal.cmp(&b.child_principal))
158                .then_with(|| a.reason.cmp(&b.reason))
159        });
160
161        paginate_vec(entries, page)
162    }
163
164    #[must_use]
165    pub fn perf_page(page: PageRequest) -> Page<PerfEntry> {
166        let snapshot = PerfOps::snapshot();
167        paginate_vec(snapshot.entries, page)
168    }
169
170    #[must_use]
171    pub fn endpoint_health_page(
172        page: PageRequest,
173        exclude_endpoint: Option<&str>,
174    ) -> Page<EndpointHealth> {
175        let snapshot = MetricsOps::endpoint_health_snapshot();
176        let mut entries = EndpointHealthMapper::record_to_view(
177            snapshot.attempts,
178            snapshot.results,
179            snapshot.access,
180            exclude_endpoint,
181        );
182
183        entries.sort_by(|a, b| a.endpoint.cmp(&b.endpoint));
184
185        paginate_vec(entries, page)
186    }
187}