use bytesize::ByteSize;
use memory_stats::memory_stats;
use serde::{Deserialize, Serialize};
use std::process;
use std::sync::LazyLock;
use std::sync::atomic::{AtomicI32, AtomicU64, Ordering};
use sysinfo::MemoryRefreshKind;
use sysinfo::{RefreshKind, System};
static ACCEPTED: LazyLock<AtomicU64> = LazyLock::new(|| AtomicU64::new(0));
static PROCESSING: LazyLock<AtomicI32> = LazyLock::new(|| AtomicI32::new(0));
pub fn accept_request() {
ACCEPTED.fetch_add(1, Ordering::Relaxed);
PROCESSING.fetch_add(1, Ordering::Relaxed);
}
pub fn end_request() {
PROCESSING.fetch_sub(1, Ordering::Relaxed);
}
pub fn get_processing_accepted() -> (i32, u64) {
let processing = PROCESSING.load(Ordering::Relaxed);
let accepted = ACCEPTED.load(Ordering::Relaxed);
(processing, accepted)
}
#[derive(Serialize, Deserialize, Debug)]
pub struct ProcessSystemInfo {
pub memory_mb: usize,
pub memory: String,
pub arch: String,
pub cpus: usize,
pub physical_cpus: usize,
pub total_memory: String,
pub used_memory: String,
pub kernel: String,
pub pid: u32,
pub threads: i64,
pub fd_count: usize,
pub tcp_count: usize,
pub tcp6_count: usize,
}
pub fn get_process_system_info() -> ProcessSystemInfo {
let pid = process::id();
cfg_if::cfg_if! {
if #[cfg(target_os = "linux")] {
let (fd_count, tcp_count, tcp6_count, threads) = if let Ok(p) = procfs::process::Process::new(pid as i32) {
let mut threads = -1_i64;
if let Ok(stat) = p.stat() {
threads = stat.num_threads;
}
(
p.fd_count().unwrap_or_default(),
p.tcp().unwrap_or_default().len(),
p.tcp6().unwrap_or_default().len(),
threads,
)
} else {
(0, 0, 0, -1_i64)
};
} else {
let (fd_count, tcp_count, tcp6_count, threads) = (0, 0, 0, -1_i64);
}
}
let mut memory = "".to_string();
let mut memory_mb = 0;
if let Some(value) = memory_stats() {
memory_mb = value.physical_mem / (1024 * 1024);
memory = ByteSize(value.physical_mem as u64).to_string();
}
let cpus = num_cpus::get();
let physical_cpus = num_cpus::get_physical();
let kind = MemoryRefreshKind::nothing().with_ram();
let mut sys =
System::new_with_specifics(RefreshKind::nothing().with_memory(kind));
sys.refresh_memory();
ProcessSystemInfo {
memory,
memory_mb,
arch: System::cpu_arch(),
cpus,
physical_cpus,
kernel: System::kernel_version().unwrap_or_default(),
total_memory: ByteSize(sys.total_memory()).to_string(),
used_memory: ByteSize(sys.used_memory()).to_string(),
pid,
threads,
fd_count,
tcp_count,
tcp6_count,
}
}
#[cfg(test)]
mod tests {
use super::*;
use pretty_assertions::assert_eq;
#[test]
fn test_get_process_system_info() {
let info = get_process_system_info();
assert_eq!(true, info.memory_mb > 0);
assert_eq!(true, !info.memory.is_empty());
assert_eq!(true, !info.arch.is_empty());
assert_eq!(true, info.cpus > 0);
assert_eq!(true, info.physical_cpus > 0);
assert_eq!(true, !info.kernel.is_empty());
assert_eq!(true, info.pid != 0);
}
#[test]
fn test_get_processing_accepted() {
let (processing, accepted) = get_processing_accepted();
assert_eq!(processing, 0);
assert_eq!(accepted, 0);
accept_request();
let (processing, accepted) = get_processing_accepted();
assert_eq!(processing, 1);
assert_eq!(accepted, 1);
end_request();
let (processing, accepted) = get_processing_accepted();
assert_eq!(processing, 0);
assert_eq!(accepted, 1);
}
}