about summary refs log tree commit diff
path: root/src/gatherer.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/gatherer.rs')
-rw-r--r--src/gatherer.rs71
1 files changed, 70 insertions, 1 deletions
diff --git a/src/gatherer.rs b/src/gatherer.rs
index 163d84b..7289f60 100644
--- a/src/gatherer.rs
+++ b/src/gatherer.rs
@@ -40,6 +40,7 @@ fn task(state: AwakeState) {
 	// I just want a graph on first boot; don't care about divisions just yet
 	make_mem_graph(&state);
 	make_net_graph(&state);
+	make_cpu_graph(&state);
 
 	// If we collected a point less than a minute ago, like after
 	// just being restarted, wait until it's been a minute
@@ -56,6 +57,7 @@ fn task(state: AwakeState) {
 	}
 
 	let mut last_netinfo: Option<Netinfo> = None;
+	let mut last_cpuinfo: Option<Cpuinfo> = None;
 
 	// this is a `let _` because otherwise the attribute was
 	// making the comiler mad
@@ -66,11 +68,14 @@ fn task(state: AwakeState) {
 		// Gather data
 		let meminfo = Meminfo::current();
 		let netinfo = Netinfo::current();
+		let cpuinfo = Cpuinfo::current();
 
 		// Print traces, y'know, for tracing
 		tracing::trace!("memory: {}MB used / {}MB total", meminfo.usage() / 1000, meminfo.total / 1000);
 		tracing::trace!("net: rx {} / tx {}", data_human_fmt(netinfo.rx_bytes), data_human_fmt(netinfo.tx_bytes));
+		tracing::trace!("cpu: user {} // nice {} // system {}", cpuinfo.user, cpuinfo.nice, cpuinfo.system);
 
+		// Store stats in database
 		if let Some(lni) = last_netinfo {
 			let rx_delta = netinfo.rx_bytes - lni.rx_bytes;
 			let tx_delta = netinfo.tx_bytes - lni.tx_bytes;
@@ -79,7 +84,15 @@ fn task(state: AwakeState) {
 		}
 		last_netinfo = Some(netinfo);
 
-		// Store stats in database
+		if let Some(lci) = last_cpuinfo {
+			let user_delta = cpuinfo.user - lci.user;
+			let nice_delta = cpuinfo.nice - lci.nice;
+			let system_delta = cpuinfo.system - lci.system;
+
+			state.database.insert_hostcpu(60, user_delta, nice_delta, system_delta);
+		}
+		last_cpuinfo = Some(cpuinfo);
+
 		state.database.insert_host_meminfo(meminfo);
 
 		// Only generate graphs every 15 minutes
@@ -87,6 +100,7 @@ fn task(state: AwakeState) {
 		if now.minute() % 15 == 0 {
 			make_mem_graph(&state);
 			make_net_graph(&state);
+			make_cpu_graph(&state);
 		}
 
 		std::thread::sleep(Duration::from_secs(60));
@@ -159,6 +173,26 @@ pub fn make_net_graph(state: &AwakeState) {
 	gif.save(path).unwrap();
 }
 
+pub fn make_cpu_graph(state: &AwakeState) {
+	tracing::debug!("generating cpuinfo graph");
+
+	let infos = state.database.get_last_n_hostcpu(256);
+
+	let now = OffsetDateTime::now_utc();
+	let cleaned = clean_series(&infos, |cpu| cpu.stamp, now);
+	// Scalling by 10 because the graph system does not like to have a max of only 100 due to some bad programming
+	let mut usages = extract(&cleaned, |cpu| (cpu.average_usage() * 10.0) as usize);
+
+	// Reversing here because we want latest valeus on on the
+	// right side, so last in the array
+	usages.reverse();
+
+	let gif = griph::make_1line(0, 1000, &usages);
+
+	let path = state.cache_path.join("current_hostcpuinfo.gif");
+	gif.save(path).unwrap();
+}
+
 fn clean_series<T, F>(series: &[T], time_extractor: F, end_time: OffsetDateTime) -> [Option<T>; 256]
 where
 	F: Fn(&T) -> OffsetDateTime,
@@ -292,6 +326,41 @@ impl Netinfo {
 	}
 }
 
+/// Not strictly the correct name for this, but that's fine.
+/// Structure for parsed-from /proc/stat
+pub struct Cpuinfo {
+	user: usize,
+	nice: usize,
+	system: usize,
+}
+
+impl Cpuinfo {
+	pub fn current() -> Self {
+		let procinfo = File::open("/proc/stat").unwrap();
+		let bread = BufReader::new(procinfo);
+
+		let mut cpuinfo = Cpuinfo {
+			user: 0,
+			nice: 0,
+			system: 0,
+		};
+
+		for line in bread.lines() {
+			let line = line.unwrap();
+			let Some(data) = line.strip_prefix("cpu  ") else {
+				continue;
+			};
+
+			let mut splits = data.split(' ');
+			cpuinfo.user = splits.next().unwrap().parse().unwrap();
+			cpuinfo.nice = splits.next().unwrap().parse().unwrap();
+			cpuinfo.system = splits.next().unwrap().parse().unwrap();
+		}
+
+		cpuinfo
+	}
+}
+
 fn data_human_fmt(bytes: usize) -> String {
 	let (num, unit) = data_human(bytes);
 	format!("{num}{unit}")