Files
watcheragent/WatcherAgent/src/docker/stats/cpu.rs

100 lines
3.1 KiB
Rust

use super::ContainerCpuInfo;
use bollard::query_parameters::{ListContainersOptions, StatsOptions};
use bollard::Docker;
use futures_util::stream::TryStreamExt;
use std::error::Error;
/// Get CPU statistics for all containers
pub async fn get_all_containers_cpu_stats(
docker: &Docker,
) -> Result<Vec<ContainerCpuInfo>, Box<dyn Error + Send + Sync>> {
let containers = docker
.list_containers(Some(ListContainersOptions {
all: true,
..Default::default()
}))
.await?;
let mut cpu_infos = Vec::new();
for container in containers {
let id = container.id.unwrap_or_default();
// Skip if no ID
if id.is_empty() {
continue;
}
if let Some(cpu_info) = get_single_container_cpu_stats(docker, &id).await? {
cpu_infos.push(cpu_info);
}
}
Ok(cpu_infos)
}
/// Get CPU statistics for a specific container
pub async fn get_single_container_cpu_stats(
docker: &Docker,
container_id: &str,
) -> Result<Option<ContainerCpuInfo>, Box<dyn Error + Send + Sync>> {
let mut stats_stream = docker.stats(
container_id,
Some(StatsOptions {
stream: false,
one_shot: true,
}),
);
if let Some(stats) = stats_stream.try_next().await? {
if let (Some(cpu_stats), Some(precpu_stats)) = (&stats.cpu_stats, &stats.precpu_stats) {
if let (Some(cpu_usage), Some(pre_cpu_usage)) =
(&cpu_stats.cpu_usage, &precpu_stats.cpu_usage)
{
let cpu_delta = cpu_usage
.total_usage
.unwrap_or(0)
.saturating_sub(pre_cpu_usage.total_usage.unwrap_or(0));
let system_delta = cpu_stats
.system_cpu_usage
.unwrap_or(0)
.saturating_sub(precpu_stats.system_cpu_usage.unwrap_or(0));
let online_cpus = cpu_stats.online_cpus.unwrap_or(1);
let cpu_percent = if system_delta > 0 && online_cpus > 0 {
(cpu_delta as f64 / system_delta as f64) * online_cpus as f64 * 100.0
} else {
0.0
};
return Ok(Some(ContainerCpuInfo {
container_id: Some(container_id.to_string()),
cpu_usage_percent: Some(cpu_percent),
system_cpu_usage: Some(cpu_stats.system_cpu_usage.unwrap_or(0)),
container_cpu_usage: Some(cpu_usage.total_usage.unwrap_or(0)),
online_cpus: Some(online_cpus),
}));
}
}
}
Ok(None)
}
/// Get average CPU usage across all containers
pub async fn get_average_cpu_usage(docker: &Docker) -> Result<f64, Box<dyn Error + Send + Sync>> {
let cpu_infos = get_all_containers_cpu_stats(docker).await?;
if cpu_infos.is_empty() {
return Ok(0.0);
}
let total_cpu: f64 = cpu_infos
.iter()
.map(|cpu| cpu.cpu_usage_percent.unwrap())
.sum();
Ok(total_cpu / cpu_infos.len() as f64)
}