1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
use std::path::PathBuf;
use serde::{Deserialize, Serialize};
use typeshare::typeshare;
use crate::entities::{I64, Timelength};
/// System information of a server
#[typeshare]
#[derive(Serialize, Deserialize, Debug, Clone, Default)]
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
pub struct SystemInformation {
/// The system name
pub name: Option<String>,
/// The system long os version
pub os: Option<String>,
/// System's kernel version
pub kernel: Option<String>,
/// Physical core count
pub core_count: Option<u32>,
/// Logical core count.
pub logical_core_count: Option<u32>,
/// System hostname based off DNS
pub host_name: Option<String>,
/// The CPU's brand
#[serde(default)]
pub cpu_brand: String,
/// CPU architecture (eg. x86_64, aarch64, arm64)
#[serde(default)]
pub cpu_arch: String,
}
/// System stats stored on the database.
#[typeshare]
#[derive(Serialize, Deserialize, Debug, Clone, Default)]
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
#[cfg_attr(
feature = "mongo",
derive(mongo_indexed::derive::MongoIndexed)
)]
#[cfg_attr(feature = "mongo", collection_name(Stats))]
pub struct SystemStatsRecord {
/// Unix timestamp in milliseconds
#[cfg_attr(feature = "mongo", index)]
pub ts: I64,
/// Server id
#[cfg_attr(feature = "mongo", index)]
pub sid: String,
// basic stats
/// Cpu usage percentage
pub cpu_perc: f32,
/// Load average (1m, 5m, 15m)
#[serde(default)]
pub load_average: SystemLoadAverage,
/// Memory used in GB
pub mem_used_gb: f64,
/// Total memory in GB
pub mem_total_gb: f64,
/// [2.3.0+]
/// Reclaimable page cache + buffers in GB.
#[serde(default)]
pub mem_buff_cache_gb: f64,
/// [2.3.0+]
/// ZFS ARC cache in GB. 0 when ZFS is not present.
#[serde(default)]
pub mem_zfs_arc_gb: f64,
/// [2.3.0+]
/// Total swap in GB.
#[serde(default)]
pub swap_total_gb: f64,
/// [2.3.0+]
/// Used swap in GB.
#[serde(default)]
pub swap_used_gb: f64,
/// Disk used in GB
pub disk_used_gb: f64,
/// Total disk size in GB
pub disk_total_gb: f64,
/// Breakdown of individual disks, including their usage, total size, and mount point
pub disks: Vec<SingleDiskUsage>,
/// Total network ingress in bytes
#[serde(default)]
pub network_ingress_bytes: f64,
/// Total network egress in bytes
#[serde(default)]
pub network_egress_bytes: f64,
// /// Network usage by interface name (ingress, egress in bytes)
// #[serde(default)]
// pub network_usage_interface: Vec<SingleNetworkInterfaceUsage>, // interface -> (ingress, egress)
}
/// Realtime system stats data.
#[typeshare]
#[derive(Serialize, Deserialize, Debug, Default, Clone)]
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
pub struct SystemStats {
/// Cpu usage percentage
pub cpu_perc: f32,
/// Load average (1m, 5m, 15m)
#[serde(default)]
pub load_average: SystemLoadAverage,
/// [1.15.9+]
/// Free memory in GB.
/// This is really the 'Free' memory, not the 'Available' memory.
/// It may be different than mem_total_gb - mem_used_gb.
#[serde(default)]
pub mem_free_gb: f64,
/// Used memory in GB. 'Total' - 'Available' (not free) memory,
/// with the (reclaimable) ZFS ARC cache subtracted out.
pub mem_used_gb: f64,
/// Total memory in GB
pub mem_total_gb: f64,
/// [2.3.0+]
/// Reclaimable page cache + buffers in GB.
#[serde(default)]
pub mem_buff_cache_gb: f64,
/// [2.3.0+]
/// ZFS ARC cache in GB. 0 when ZFS is not present.
#[serde(default)]
pub mem_zfs_arc_gb: f64,
/// [2.3.0+]
/// Total swap in GB.
#[serde(default)]
pub swap_total_gb: f64,
/// [2.3.0+]
/// Used swap in GB.
#[serde(default)]
pub swap_used_gb: f64,
/// Breakdown of individual disks, ie their usages, sizes, and mount points
pub disks: Vec<SingleDiskUsage>,
/// Network ingress usage in MB
#[serde(default)]
pub network_ingress_bytes: f64,
/// Network egress usage in MB
#[serde(default)]
pub network_egress_bytes: f64,
// /// Network usage by interface name (ingress, egress in bytes)
// #[serde(default)]
// pub network_usage_interface: Vec<SingleNetworkInterfaceUsage>, // interface -> (ingress, egress)
// metadata
/// The rate the system stats are being polled from the system
pub polling_rate: Timelength,
/// Unix timestamp in milliseconds when stats were last polled
pub refresh_ts: I64,
/// Unix timestamp in milliseconds when disk list was last refreshed
pub refresh_list_ts: I64,
}
/// Realtime minimal system stats data (zero allocation)
#[typeshare]
#[derive(Serialize, Deserialize, Debug, Default, Clone, Copy)]
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
pub struct MinimalSystemStats {
/// Cpu usage percentage
pub cpu_perc: f32,
/// Load average (1m, 5m, 15m)
pub load_average: SystemLoadAverage,
/// This is really the 'Free' memory, not the 'Available' memory.
/// It may be different than mem_total_gb - mem_used_gb.
pub mem_free_gb: f64,
/// Used memory in GB. 'Total' - 'Available' (not free) memory,
/// with the (reclaimable) ZFS ARC cache subtracted out.
pub mem_used_gb: f64,
/// Total memory in GB
pub mem_total_gb: f64,
/// Reclaimable page cache + buffers in GB.
pub mem_buff_cache_gb: f64,
/// ZFS ARC cache in GB. 0 when ZFS is not present.
pub mem_zfs_arc_gb: f64,
/// Total swap in GB.
pub swap_total_gb: f64,
/// Used swap in GB.
pub swap_used_gb: f64,
/// Total size of all disks combined in GB
pub disk_total_gb: f64,
/// Used portion of all disks combined in GB
pub disk_used_gb: f64,
/// Network ingress usage in MB
pub network_ingress_bytes: f64,
/// Network egress usage in MB
pub network_egress_bytes: f64,
/// The rate the system stats are being polled from the system
pub polling_rate: Timelength,
/// Unix timestamp in milliseconds when stats were last polled
pub refresh_ts: I64,
/// Unix timestamp in milliseconds when disk list was last refreshed
pub refresh_list_ts: I64,
}
impl From<&SystemStats> for MinimalSystemStats {
fn from(value: &SystemStats) -> Self {
Self {
cpu_perc: value.cpu_perc,
load_average: value.load_average,
mem_free_gb: value.mem_free_gb,
mem_used_gb: value.mem_used_gb,
mem_total_gb: value.mem_total_gb,
mem_buff_cache_gb: value.mem_buff_cache_gb,
mem_zfs_arc_gb: value.mem_zfs_arc_gb,
swap_total_gb: value.swap_total_gb,
swap_used_gb: value.swap_used_gb,
disk_total_gb: value
.disks
.iter()
.fold(0.0, |total, disk| total + disk.total_gb),
disk_used_gb: value
.disks
.iter()
.fold(0.0, |used, disk| used + disk.used_gb),
network_ingress_bytes: value.network_ingress_bytes,
network_egress_bytes: value.network_egress_bytes,
polling_rate: value.polling_rate,
refresh_ts: value.refresh_ts,
refresh_list_ts: value.refresh_list_ts,
}
}
}
/// Info for a single disk mounted on the system.
#[typeshare]
#[derive(Serialize, Deserialize, Debug, Clone)]
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
pub struct SingleDiskUsage {
/// The mount point of the disk
#[cfg_attr(feature = "utoipa", schema(value_type = String))]
pub mount: PathBuf,
/// Detected file system
pub file_system: String,
/// Used portion of the disk in GB
pub used_gb: f64,
/// Total size of the disk in GB
pub total_gb: f64,
}
/// Info for network interface usage.
#[typeshare]
#[derive(Serialize, Deserialize, Debug, Clone)]
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
pub struct SingleNetworkInterfaceUsage {
/// The network interface name
pub name: String,
/// The ingress in bytes
pub ingress_bytes: f64,
/// The egress in bytes
pub egress_bytes: f64,
}
pub fn sum_disk_usage(disks: &[SingleDiskUsage]) -> TotalDiskUsage {
disks
.iter()
.fold(TotalDiskUsage::default(), |mut total, disk| {
total.used_gb += disk.used_gb;
total.total_gb += disk.total_gb;
total
})
}
/// Info for the all system disks combined.
#[typeshare]
#[derive(Serialize, Deserialize, Debug, Default, Clone)]
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
pub struct TotalDiskUsage {
/// Used portion in GB
pub used_gb: f64,
/// Total size in GB
pub total_gb: f64,
}
/// Information about a process on the system.
#[typeshare]
#[derive(Serialize, Deserialize, Debug, Clone)]
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
pub struct SystemProcess {
/// The process PID
pub pid: u32,
/// The process name
pub name: String,
/// The path to the process executable
#[serde(default)]
pub exe: String,
/// The command used to start the process
pub cmd: Vec<String>,
/// The time the process was started
#[serde(default)]
pub start_time: f64,
/// The cpu usage percentage of the process.
/// This is in core-percentage, eg 100% is 1 full core, and
/// an 8 core machine would max at 800%.
pub cpu_perc: f32,
/// The memory usage of the process in MB
pub mem_mb: f64,
/// Process disk read in KB/s
pub disk_read_kb: f64,
/// Process disk write in KB/s
pub disk_write_kb: f64,
}
#[typeshare]
#[derive(Serialize, Deserialize, Debug, Default, Clone, Copy)]
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
pub struct SystemLoadAverage {
/// 1m load average
pub one: f64,
/// 5m load average
pub five: f64,
/// 15m load average
pub fifteen: f64,
}