use chrono::Local;
use once_cell::sync::Lazy;
use std::fs;
use crate::device::container_info::ContainerInfo;
use crate::device::{MemoryInfo, MemoryReader};
use crate::utils::get_hostname;
static CONTAINER_INFO: Lazy<Option<ContainerInfo>> = Lazy::new(|| {
let info = ContainerInfo::detect();
if info.is_container { Some(info) } else { None }
});
pub struct LinuxMemoryReader {
container_info: &'static Option<ContainerInfo>,
}
impl Default for LinuxMemoryReader {
fn default() -> Self {
Self::new()
}
}
impl LinuxMemoryReader {
pub fn new() -> Self {
LinuxMemoryReader {
container_info: &CONTAINER_INFO,
}
}
}
impl MemoryReader for LinuxMemoryReader {
fn get_memory_info(&self) -> Vec<MemoryInfo> {
let mut memory_info = Vec::new();
if let Some(container_info) = self.container_info
&& let Some((total, used, utilization)) = container_info.get_memory_stats()
{
let hostname = get_hostname();
let now = Local::now();
memory_info.push(MemoryInfo {
index: 0, host_id: hostname.clone(),
hostname: hostname.clone(),
instance: hostname,
total_bytes: total,
used_bytes: used,
available_bytes: total.saturating_sub(used),
free_bytes: total.saturating_sub(used),
buffers_bytes: 0, cached_bytes: 0, swap_total_bytes: 0, swap_used_bytes: 0,
swap_free_bytes: 0,
utilization,
time: now.format("%Y-%m-%d %H:%M:%S").to_string(),
});
return memory_info;
}
if let Ok(meminfo_content) = fs::read_to_string("/proc/meminfo") {
let mut total_bytes = 0;
let mut available_bytes = 0;
let mut free_bytes = 0;
let mut buffers_bytes = 0;
let mut cached_bytes = 0;
let mut swap_total_bytes = 0;
let mut swap_free_bytes = 0;
for line in meminfo_content.lines() {
let parts: Vec<&str> = line.split_whitespace().collect();
if parts.len() >= 2 {
let key = parts[0].trim_end_matches(':');
if let Ok(value) = parts[1].parse::<u64>() {
let value_bytes = value * 1024;
match key {
"MemTotal" => total_bytes = value_bytes,
"MemAvailable" => available_bytes = value_bytes,
"MemFree" => free_bytes = value_bytes,
"Buffers" => buffers_bytes = value_bytes,
"Cached" => cached_bytes = value_bytes,
"SwapTotal" => swap_total_bytes = value_bytes,
"SwapFree" => swap_free_bytes = value_bytes,
_ => {}
}
}
}
}
let used_bytes = total_bytes - available_bytes;
let swap_used_bytes = swap_total_bytes - swap_free_bytes;
let utilization = if total_bytes > 0 {
(used_bytes as f64 / total_bytes as f64) * 100.0
} else {
0.0
};
let hostname = get_hostname();
let now = Local::now();
memory_info.push(MemoryInfo {
index: 0, host_id: hostname.clone(), hostname: hostname.clone(),
instance: hostname,
total_bytes,
used_bytes,
available_bytes,
free_bytes,
buffers_bytes,
cached_bytes,
swap_total_bytes,
swap_used_bytes,
swap_free_bytes,
utilization,
time: now.format("%Y-%m-%d %H:%M:%S").to_string(),
});
}
memory_info
}
}
#[cfg(test)]
#[path = "memory_linux/tests.rs"]
mod tests;