90 lines
2.8 KiB
Rust
90 lines
2.8 KiB
Rust
use crate::docker;
|
|
use crate::process::{self, ProcInfo};
|
|
use std::collections::HashMap;
|
|
use std::time::Duration;
|
|
use tokio::sync::mpsc;
|
|
use tokio::task;
|
|
use tokio::time::sleep;
|
|
|
|
#[derive(Clone, Copy, Default, Debug, PartialEq)]
|
|
pub struct StackInfo {
|
|
pub containers: u32,
|
|
pub running_containers: u32,
|
|
pub stopped_containers: u32,
|
|
pub process_count: u32,
|
|
pub cpu_percent: f64,
|
|
pub memory_usage: usize,
|
|
pub memory_percent: f64,
|
|
}
|
|
|
|
pub fn spawn_monitor(stack: docker::Stack) -> mpsc::Receiver<StackInfo> {
|
|
let (tx, rx) = mpsc::channel(64);
|
|
|
|
task::spawn(monitor_proc(tx, stack));
|
|
|
|
rx
|
|
}
|
|
|
|
async fn monitor_proc(tx: mpsc::Sender<StackInfo>, stack: docker::Stack) -> anyhow::Result<()> {
|
|
let mut proc_monitors: HashMap<u32, mpsc::Receiver<ProcInfo>> = HashMap::new();
|
|
let mut processes = HashMap::<u32, ProcInfo>::new();
|
|
let mut last_stack_info = StackInfo::default();
|
|
|
|
loop {
|
|
let mut stack_info = StackInfo::default();
|
|
|
|
let containers = docker::list_containers(&stack).await?;
|
|
stack_info.containers = containers.len() as u32;
|
|
stack_info.running_containers = containers.iter().filter(|c| c.is_running()).count() as u32;
|
|
stack_info.stopped_containers = stack_info.containers - stack_info.running_containers;
|
|
|
|
processes.clear();
|
|
for container in &containers {
|
|
for process in docker::list_processes(&stack, container).await? {
|
|
processes.insert(process.pid, Default::default());
|
|
if !proc_monitors.contains_key(&process.pid) {
|
|
proc_monitors.insert(process.pid, process::spawn_monitor(process.pid));
|
|
}
|
|
}
|
|
}
|
|
|
|
proc_monitors.retain(|&pid, monitor| {
|
|
if !processes.contains_key(&pid) {
|
|
return false;
|
|
}
|
|
|
|
match monitor.try_recv() {
|
|
Ok(info) => {
|
|
processes.insert(pid, info);
|
|
true
|
|
}
|
|
Err(mpsc::error::TryRecvError::Empty) => true,
|
|
Err(_) => false,
|
|
}
|
|
});
|
|
|
|
let memory_usage = processes.values().map(|p| p.memory_usage).sum();
|
|
let host_memory = (1usize << 20) * 16; // 10 GiB // TODO
|
|
|
|
stack_info = StackInfo {
|
|
process_count: processes.len() as u32,
|
|
memory_usage,
|
|
memory_percent: memory_usage as f64 / host_memory as f64,
|
|
cpu_percent: processes
|
|
.values()
|
|
.map(|p| p.cpu_percent)
|
|
.sum::<f64>()
|
|
.max(0.0),
|
|
..stack_info
|
|
};
|
|
|
|
if stack_info != last_stack_info {
|
|
last_stack_info = stack_info;
|
|
|
|
tx.send(stack_info).await?;
|
|
}
|
|
|
|
sleep(Duration::from_secs(1)).await;
|
|
}
|
|
}
|