Skip to main content

ic_query/ic/model/requests/
metrics.rs

1//! Module: ic::model::requests::metrics
2//!
3//! Responsibility: bounded official Dashboard Metrics API request contracts.
4//! Does not own: network resources, canister discovery, transport, or reports.
5//! Boundary: captures one selected aggregate metric and its explicit observation window.
6
7use serde::Serialize;
8use std::{fmt, str::FromStr};
9
10///
11/// IcMetricKind
12///
13/// One bounded network metric exposed by the official Dashboard Metrics API.
14///
15
16#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, Serialize)]
17#[serde(rename_all = "kebab-case")]
18pub enum IcMetricKind {
19    /// Network instruction execution rate.
20    InstructionRate,
21    /// Network message execution rate.
22    MessageExecutionRate,
23    /// Network cycle burn rate.
24    CycleBurnRate,
25    /// Network block ingestion rate.
26    BlockRate,
27    /// Total and currently up node counts.
28    IcNodeCount,
29    /// Total Subnet count.
30    IcSubnetTotal,
31    /// Running and stopped canister counts.
32    RegisteredCanistersCount,
33    /// Total estimated IC energy-consumption rate in kWh.
34    TotalIcEnergyConsumptionRateKwh,
35    /// Active boundary-node count.
36    BoundaryNodesCount,
37}
38
39impl IcMetricKind {
40    /// Return every metric supported by the bounded report adapter.
41    #[must_use]
42    pub const fn all() -> [Self; 9] {
43        [
44            Self::InstructionRate,
45            Self::MessageExecutionRate,
46            Self::CycleBurnRate,
47            Self::BlockRate,
48            Self::IcNodeCount,
49            Self::IcSubnetTotal,
50            Self::RegisteredCanistersCount,
51            Self::TotalIcEnergyConsumptionRateKwh,
52            Self::BoundaryNodesCount,
53        ]
54    }
55
56    /// Return the official Dashboard Metrics API path name.
57    #[must_use]
58    pub const fn as_str(self) -> &'static str {
59        match self {
60            Self::InstructionRate => "instruction-rate",
61            Self::MessageExecutionRate => "message-execution-rate",
62            Self::CycleBurnRate => "cycle-burn-rate",
63            Self::BlockRate => "block-rate",
64            Self::IcNodeCount => "ic-node-count",
65            Self::IcSubnetTotal => "ic-subnet-total",
66            Self::RegisteredCanistersCount => "registered-canisters-count",
67            Self::TotalIcEnergyConsumptionRateKwh => "total-ic-energy-consumption-rate-kwh",
68            Self::BoundaryNodesCount => "boundary-nodes-count",
69        }
70    }
71
72    #[cfg(feature = "host")]
73    pub(crate) const fn series_names(self) -> &'static [&'static str] {
74        match self {
75            Self::InstructionRate => &["instruction_rate"],
76            Self::MessageExecutionRate => &["message_execution_rate"],
77            Self::CycleBurnRate => &["cycle_burn_rate"],
78            Self::BlockRate => &["block_rate"],
79            Self::IcNodeCount => &["total_nodes", "up_nodes"],
80            Self::IcSubnetTotal => &["ic_subnet_total"],
81            Self::RegisteredCanistersCount => &["running_canisters", "stopped_canisters"],
82            Self::TotalIcEnergyConsumptionRateKwh => &["energy_consumption_rate"],
83            Self::BoundaryNodesCount => &["boundary_nodes_count"],
84        }
85    }
86}
87
88impl fmt::Display for IcMetricKind {
89    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
90        formatter.write_str(self.as_str())
91    }
92}
93
94impl FromStr for IcMetricKind {
95    type Err = String;
96
97    fn from_str(value: &str) -> Result<Self, Self::Err> {
98        Self::all()
99            .into_iter()
100            .find(|metric| metric.as_str() == value)
101            .ok_or_else(|| format!("unsupported IC Dashboard metric {value:?}"))
102    }
103}
104
105///
106/// IcMetricQuery
107///
108/// One explicitly bounded official Dashboard metric time-series query.
109///
110
111#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
112pub struct IcMetricQuery {
113    /// Official Dashboard metric to retrieve.
114    pub metric: IcMetricKind,
115    /// Inclusive query start as Unix seconds.
116    pub start_unix_secs: u64,
117    /// Inclusive query end as Unix seconds.
118    pub end_unix_secs: u64,
119    /// Requested observation interval in seconds.
120    pub step_secs: u32,
121}
122
123impl IcMetricQuery {
124    /// Construct one explicit metric query window.
125    #[must_use]
126    pub const fn new(
127        metric: IcMetricKind,
128        start_unix_secs: u64,
129        end_unix_secs: u64,
130        step_secs: u32,
131    ) -> Self {
132        Self {
133            metric,
134            start_unix_secs,
135            end_unix_secs,
136            step_secs,
137        }
138    }
139}
140
141///
142/// IcMetricRequest
143///
144/// Request accepted by the bounded official Dashboard metric report builder.
145///
146
147#[derive(Clone, Debug, Eq, PartialEq)]
148pub struct IcMetricRequest {
149    /// Dashboard Metrics API base endpoint.
150    pub source_endpoint: String,
151    /// Collection time as Unix seconds.
152    pub now_unix_secs: u64,
153    /// Explicitly bounded metric query.
154    pub query: IcMetricQuery,
155}
156
157impl IcMetricRequest {
158    /// Construct one bounded live Dashboard metric request.
159    #[must_use]
160    pub fn new(
161        source_endpoint: impl Into<String>,
162        now_unix_secs: u64,
163        query: IcMetricQuery,
164    ) -> Self {
165        Self {
166            source_endpoint: source_endpoint.into(),
167            now_unix_secs,
168            query,
169        }
170    }
171}