1use serde::{Deserialize, Serialize};
2use std::collections::HashMap;
3
4#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
6pub struct Stats {
7 pub id: String,
8 pub name: String,
9 pub read: String,
10 pub networks: Option<HashMap<String, Network>>,
11 #[serde(with = "format::memory_stats")]
12 pub memory_stats: Option<MemoryStats>,
13 pub cpu_stats: CpuStats,
14 pub precpu_stats: CpuStats,
17 pub blkio_stats: BlkioStats,
18 pub pids_stats: PidsStats,
20}
21
22impl Stats {
23 pub fn used_memory(&self) -> Option<u64> {
24 self.memory_stats
25 .as_ref()
26 .map(|mem| mem.usage - mem.stats.cache)
27 }
28 pub fn available_memory(&self) -> Option<u64> {
29 self.memory_stats.as_ref().map(|mem| mem.limit)
30 }
31 pub fn memory_usage(&self) -> Option<f64> {
33 if let (Some(used_memory), Some(available_memory)) =
34 (self.used_memory(), self.available_memory())
35 {
36 Some((used_memory as f64 / available_memory as f64) * 100.0)
37 } else {
38 None
39 }
40 }
41 pub fn cpu_delta(&self) -> u64 {
42 self.cpu_stats.cpu_usage.total_usage - self.precpu_stats.cpu_usage.total_usage
43 }
44 pub fn system_cpu_delta(&self) -> Option<u64> {
45 if let (Some(cpu), Some(pre)) = (
46 self.cpu_stats.system_cpu_usage,
47 self.precpu_stats.system_cpu_usage,
48 ) {
49 Some(cpu - pre)
50 } else {
51 None
52 }
53 }
54 pub fn number_cpus(&self) -> u64 {
57 if let Some(cpus) = self.cpu_stats.online_cpus {
58 cpus
59 } else {
60 let empty = &[];
61 self.cpu_stats
62 .cpu_usage
63 .percpu_usage
64 .as_deref()
65 .unwrap_or(empty)
66 .len() as u64
67 }
68 }
69 pub fn cpu_usage(&self) -> Option<f64> {
71 self.system_cpu_delta().map(|system_cpu_delta| {
72 (self.cpu_delta() as f64 / system_cpu_delta as f64) * self.number_cpus() as f64 * 100.0
73 })
74 }
75}
76
77#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Serialize, Deserialize)]
78pub struct Network {
79 pub rx_dropped: u64,
80 pub rx_bytes: u64,
81 pub rx_errors: u64,
82 pub tx_packets: u64,
83 pub tx_dropped: u64,
84 pub rx_packets: u64,
85 pub tx_errors: u64,
86 pub tx_bytes: u64,
87}
88
89#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Serialize, Deserialize)]
90pub struct MemoryStats {
91 pub max_usage: u64,
92 pub usage: u64,
93 #[serde(skip_serializing_if = "Option::is_none")]
94 pub failcnt: Option<u64>,
95 pub limit: u64,
96 pub stats: MemoryStat,
97}
98
99#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Serialize, Deserialize)]
100pub struct MemoryStat {
101 pub total_pgmajfault: u64,
102 pub cache: u64,
103 pub mapped_file: u64,
104 pub total_inactive_file: u64,
105 pub pgpgout: u64,
106 pub rss: u64,
107 pub total_mapped_file: u64,
108 pub writeback: u64,
109 pub unevictable: u64,
110 pub pgpgin: u64,
111 pub total_unevictable: u64,
112 pub pgmajfault: u64,
113 pub total_rss: u64,
114 pub total_rss_huge: u64,
115 pub total_writeback: u64,
116 pub total_inactive_anon: u64,
117 pub rss_huge: u64,
118 pub hierarchical_memory_limit: u64,
119 pub total_pgfault: u64,
120 pub total_active_file: u64,
121 pub active_anon: u64,
122 pub total_active_anon: u64,
123 pub total_pgpgout: u64,
124 pub total_cache: u64,
125 pub inactive_anon: u64,
126 pub active_file: u64,
127 pub pgfault: u64,
128 pub inactive_file: u64,
129 pub total_pgpgin: u64,
130}
131
132#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Serialize, Deserialize)]
133pub struct CpuStats {
134 pub cpu_usage: CpuUsage,
135 #[serde(skip_serializing_if = "Option::is_none")]
136 pub system_cpu_usage: Option<u64>,
137 #[serde(skip_serializing_if = "Option::is_none")]
138 pub online_cpus: Option<u64>,
139 pub throttling_data: ThrottlingData,
140}
141
142#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Serialize, Deserialize)]
143pub struct CpuUsage {
144 #[serde(skip_serializing_if = "Option::is_none")]
145 pub percpu_usage: Option<Vec<u64>>,
146 pub usage_in_usermode: u64,
147 pub total_usage: u64,
148 pub usage_in_kernelmode: u64,
149}
150
151#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Serialize, Deserialize)]
152pub struct ThrottlingData {
153 pub periods: u64,
154 pub throttled_periods: u64,
155 pub throttled_time: u64,
156}
157
158#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Serialize, Deserialize)]
159pub struct BlkioStats {
160 pub io_service_bytes_recursive: Option<Vec<BlkioStat>>,
161 pub io_serviced_recursive: Option<Vec<BlkioStat>>,
162 pub io_queue_recursive: Option<Vec<BlkioStat>>,
163 pub io_service_time_recursive: Option<Vec<BlkioStat>>,
164 pub io_wait_time_recursive: Option<Vec<BlkioStat>>,
165 pub io_merged_recursive: Option<Vec<BlkioStat>>,
166 pub io_time_recursive: Option<Vec<BlkioStat>>,
167 pub sectors_recursive: Option<Vec<BlkioStat>>,
168}
169
170#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Serialize, Deserialize)]
171pub struct BlkioStat {
172 pub major: u64,
173 pub minor: u64,
174 pub op: String,
175 pub value: u64,
176}
177
178#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Serialize, Deserialize)]
179pub struct PidsStats {
180 #[serde(skip_serializing_if = "Option::is_none")]
181 pub current: Option<u64>,
182}
183
184mod format {
185 use super::*;
186 use serde::de::{DeserializeOwned, Deserializer};
187 use serde::ser::{Serialize, Serializer};
188
189 pub mod memory_stats {
190 use super::*;
191
192 #[derive(Debug, Serialize, Deserialize)]
193 #[serde(untagged)]
194 enum Plus1<T> {
195 Item(T),
196 Empty {},
197 }
198
199 impl<T> From<Plus1<T>> for Option<T> {
200 fn from(value: Plus1<T>) -> Option<T> {
201 match value {
202 Plus1::Item(t) => Some(t),
203 Plus1::Empty {} => None,
204 }
205 }
206 }
207
208 impl<T> From<Option<T>> for Plus1<T> {
209 fn from(value: Option<T>) -> Plus1<T> {
210 match value {
211 Option::Some(t) => Plus1::Item(t),
212 Option::None => Plus1::Empty {},
213 }
214 }
215 }
216
217 pub fn deserialize<'de, D, T>(de: D) -> std::result::Result<Option<T>, D::Error>
218 where
219 D: Deserializer<'de>,
220 T: DeserializeOwned,
221 {
222 Plus1::<T>::deserialize(de).map(Into::into)
223 }
224
225 pub fn serialize<T, S>(t: &Option<T>, se: S) -> std::result::Result<S::Ok, S::Error>
226 where
227 S: Serializer,
228 T: Serialize,
229 {
230 Into::<Plus1<&T>>::into(t.as_ref()).serialize(se)
231 }
232 }
233}