From 540356b9486b08c64db7d2dc3bbc8ba92aed4523 Mon Sep 17 00:00:00 2001
From: hinto-janaiyo <hinto.janaiyo@protonmail.com>
Date: Mon, 12 Dec 2022 14:34:17 -0500
Subject: [PATCH] litter codebase with [debug!()]

The entire codebase is now littered with [debug!()] messages.
Thankfully [log] has 0 cost if you aren't using them, so regular
users won't have a runtime penalty unless they specify RUST_LOG=debug.
---
 README.md     |   2 +-
 src/gupax.rs  |   5 ++
 src/helper.rs | 160 +++++++++++++++++++++++++++++++++++++-------------
 src/main.rs   |  35 +++++++++++
 src/node.rs   |  27 +++++----
 src/p2pool.rs |  16 +++--
 src/status.rs |   4 ++
 src/xmrig.rs  |  16 +++--
 8 files changed, 203 insertions(+), 62 deletions(-)

diff --git a/README.md b/README.md
index bba4b3b..9fa440f 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,6 @@
 # WORK IN PROGRESS - ETA: December 25th, 2022
 ![banner.png](https://github.com/hinto-janaiyo/gupax/blob/main/images/banner.png)
-Gupax (*guh-picks*) is a (Windows|macOS|Linux) GUI for mining [**Monero**](https://github.com/monero-project/monero) on [**P2Pool**](https://github.com/SChernykh/p2pool), using [**XMRig**](https://github.com/xmrig/xmrig).
+Gupax is a (Windows|macOS|Linux) GUI for mining [**Monero**](https://github.com/monero-project/monero) on [**P2Pool**](https://github.com/SChernykh/p2pool), using [**XMRig**](https://github.com/xmrig/xmrig).
 
 **If you just want to see a short 1-minute video on how to download and run Gupax: [click here.](#Video)**
 
diff --git a/src/gupax.rs b/src/gupax.rs
index 8cdc6e5..6fecf39 100644
--- a/src/gupax.rs
+++ b/src/gupax.rs
@@ -83,6 +83,7 @@ pub enum Ratio {
 impl Gupax {
 	pub fn show(&mut self, og: &Arc<Mutex<State>>, state_path: &Path, update: &Arc<Mutex<Update>>, file_window: &Arc<Mutex<FileWindow>>, error_state: &mut ErrorState, restart: &Arc<Mutex<Restart>>, width: f32, height: f32, frame: &mut eframe::Frame, ctx: &egui::Context, ui: &mut egui::Ui) {
 		// Update button + Progress bar
+		debug!("Gupax Tab | Rendering [Update] button + progress bar");
 		ui.group(|ui| {
 				// These are in unnecessary [ui.vertical()]'s
 				// because I need to use [ui.set_enabled]s, but I can't
@@ -112,6 +113,7 @@ impl Gupax {
 				});
 		});
 
+		debug!("Gupax Tab | Rendering bool buttons");
 		ui.horizontal(|ui| {
 			ui.group(|ui| {
 					let width = (width - SPACE*12.0)/6.0;
@@ -133,6 +135,7 @@ impl Gupax {
 
 		if self.simple { return }
 
+		debug!("Gupax Tab | Rendering P2Pool/XMRig path selection");
 		// P2Pool/XMRig binary path selection
 		ui.add_space(SPACE);
 		ui.style_mut().override_text_style = Some(Monospace);
@@ -182,6 +185,7 @@ impl Gupax {
 		drop(guard);
 
 		// Gupax App resolution sliders
+		debug!("Gupax Tab | Rendering resolution sliders");
 		ui.vertical(|ui| {
 			let width = width/10.0;
 			ui.spacing_mut().icon_width = width / 25.0;
@@ -229,6 +233,7 @@ impl Gupax {
 			}
 		})});
 		// Saved [Tab]
+		debug!("Gupax Tab | Rendering [Tab] selector");
 		ui.group(|ui| {
 			let height = ui.available_height()/1.85;
 			let width = (width/5.0)-(SPACE*1.93);
diff --git a/src/helper.rs b/src/helper.rs
index c52ee16..02be2b9 100644
--- a/src/helper.rs
+++ b/src/helper.rs
@@ -251,6 +251,7 @@ impl Helper {
 	// The actual [String] holds 56_000_000, but this allows for some leeway so it doesn't allocate more memory.
 	// This will also append a message showing it was reset.
 	fn check_reset_output_full(output_full: &Arc<Mutex<String>>, name: ProcessName) {
+		debug!("{} Watchdog | Resetting [output_full]...", name);
 		let mut output_full = output_full.lock().unwrap();
 		if output_full.len() > PROCESS_OUTPUT_LEEWAY {
 			info!("{} | Output is nearing {} bytes, resetting!", MAX_PROCESS_OUTPUT_BYTES, name);
@@ -258,10 +259,12 @@ impl Helper {
 			output_full.clear();
 			output_full.push_str(&text);
 		}
+		debug!("{} Watchdog | Resetting [output_full] ... OK", name);
 	}
 
 	// For the GUI thread
 	fn check_reset_gui_p2pool_output(gui_api: &Arc<Mutex<PubP2poolApi>>) {
+		debug!("P2Pool Watchdog | Resetting GUI output...");
 		let mut gui_api = gui_api.lock().unwrap();
 		if gui_api.output.len() > GUI_OUTPUT_LEEWAY {
 			info!("P2Pool | Output is nearing {} bytes, resetting!", MAX_GUI_OUTPUT_BYTES);
@@ -269,9 +272,11 @@ impl Helper {
 			gui_api.output.clear();
 			gui_api.output.push_str(&text);
 		}
+		debug!("P2Pool Watchdog | Resetting GUI output ... OK");
 	}
 
 	fn check_reset_gui_xmrig_output(gui_api: &Arc<Mutex<PubXmrigApi>>) {
+		debug!("XMRig Watchdog | Resetting GUI output...");
 		let mut gui_api = gui_api.lock().unwrap();
 		if gui_api.output.len() > GUI_OUTPUT_LEEWAY {
 			info!("XMRig | Output is nearing {} bytes, resetting!", MAX_GUI_OUTPUT_BYTES);
@@ -279,6 +284,7 @@ impl Helper {
 			gui_api.output.clear();
 			gui_api.output.push_str(&text);
 		}
+		debug!("XMRig Watchdog | Resetting GUI output ... OK");
 	}
 
 	//---------------------------------------------------------------------------------------------------- P2Pool specific
@@ -306,6 +312,7 @@ impl Helper {
 				thread::sleep(SECOND);
 			}
 			// Ok, process is not alive, start the new one!
+			info!("P2Pool | Old process seems dead, starting new one!");
 			Self::start_p2pool(&helper, &state, &path);
 		});
 		info!("P2Pool | Restart ... OK");
@@ -418,6 +425,7 @@ impl Helper {
 	// The P2Pool watchdog. Spawns 1 OS thread for reading a PTY (STDOUT+STDERR), and combines the [Child] with a PTY so STDIN actually works.
 	fn spawn_p2pool_watchdog(process: Arc<Mutex<Process>>, gui_api: Arc<Mutex<PubP2poolApi>>, pub_api: Arc<Mutex<PubP2poolApi>>, priv_api: Arc<Mutex<PrivP2poolApi>>, args: Vec<String>, mut path: std::path::PathBuf) {
 		// 1a. Create PTY
+		debug!("P2Pool | Creating PTY...");
 		let pty = portable_pty::native_pty_system();
 		let pair = pty.openpty(portable_pty::PtySize {
 			rows: 100,
@@ -426,13 +434,16 @@ impl Helper {
 			pixel_height: 0,
 		}).unwrap();
 		// 1b. Create command
+		debug!("P2Pool | Creating command...");
 		let mut cmd = portable_pty::CommandBuilder::new(path.as_path());
 		cmd.args(args);
 		cmd.cwd(path.as_path().parent().unwrap());
 		// 1c. Create child
+		debug!("P2Pool | Creating child...");
 		let child_pty = Arc::new(Mutex::new(pair.slave.spawn_command(cmd).unwrap()));
 
         // 2. Set process state
+		debug!("P2Pool | Setting process state...");
         let mut lock = process.lock().unwrap();
         lock.state = ProcessState::Alive;
         lock.signal = ProcessSignal::None;
@@ -443,6 +454,7 @@ impl Helper {
 		drop(lock);
 
 		// 3. Spawn PTY read thread
+		debug!("P2Pool | Spawning PTY read thread...");
 		let output_full = Arc::clone(&process.lock().unwrap().output_full);
 		let output_buf = Arc::clone(&process.lock().unwrap().output_buf);
 		thread::spawn(move || {
@@ -453,6 +465,8 @@ impl Helper {
 
 		path.pop();
 		path.push(P2POOL_API_PATH);
+
+		debug!("P2Pool | Cleaning old API files...");
 		// Attempt to remove stale API file
 		match std::fs::remove_file(&path) {
 			Ok(_) => info!("P2Pool | Attempting to remove stale API file ... OK"),
@@ -475,9 +489,27 @@ impl Helper {
 		loop {
 			// Set timer
 			let now = Instant::now();
+			debug!("P2Pool Watchdog | ----------- Start of loop -----------");
+
+			// Check if the process is secretly died without us knowing :)
+			if let Ok(Some(code)) = child_pty.lock().unwrap().try_wait() {
+				debug!("P2Pool Watchdog | Process secretly died! Getting exit status");
+				let exit_status = match code.success() {
+					true  => { process.lock().unwrap().state = ProcessState::Dead; "Successful" },
+					false => { process.lock().unwrap().state = ProcessState::Failed; "Failed" },
+				};
+				let uptime = HumanTime::into_human(start.elapsed());
+				info!("P2Pool Watchdog | Stopped ... Uptime was: [{}], Exit status: [{}]", uptime, exit_status);
+				// This is written directly into the GUI, because sometimes the 900ms event loop can't catch it.
+				writeln!(gui_api.lock().unwrap().output, "{}\nP2Pool stopped | Uptime: [{}] | Exit status: [{}]\n{}\n\n\n\n", HORI_CONSOLE, uptime, exit_status, HORI_CONSOLE);
+				process.lock().unwrap().signal = ProcessSignal::None;
+				debug!("P2Pool Watchdog | Secret dead process reap OK, breaking");
+				break
+			}
 
 			// Check SIGNAL
 			if process.lock().unwrap().signal == ProcessSignal::Stop {
+				debug!("P2Pool Watchdog | Stop SIGNAL caught");
 				child_pty.lock().unwrap().kill(); // This actually sends a SIGHUP to p2pool (closes the PTY, hangs up on p2pool)
 				// Wait to get the exit status
 				let exit_status = match child_pty.lock().unwrap().wait() {
@@ -491,13 +523,15 @@ impl Helper {
 					_ => { process.lock().unwrap().state = ProcessState::Failed; "Unknown Error" },
 				};
 				let uptime = HumanTime::into_human(start.elapsed());
-				info!("P2Pool | Stopped ... Uptime was: [{}], Exit status: [{}]", uptime, exit_status);
+				info!("P2Pool Watchdog | Stopped ... Uptime was: [{}], Exit status: [{}]", uptime, exit_status);
 				// This is written directly into the GUI API, because sometimes the 900ms event loop can't catch it.
 				writeln!(gui_api.lock().unwrap().output, "{}\nP2Pool stopped | Uptime: [{}] | Exit status: [{}]\n{}\n\n\n\n", HORI_CONSOLE, uptime, exit_status, HORI_CONSOLE);
 				process.lock().unwrap().signal = ProcessSignal::None;
+				debug!("P2Pool Watchdog | Stop SIGNAL done, breaking");
 				break
 			// Check RESTART
 			} else if process.lock().unwrap().signal == ProcessSignal::Restart {
+				debug!("P2Pool Watchdog | Restart SIGNAL caught");
 				child_pty.lock().unwrap().kill(); // This actually sends a SIGHUP to p2pool (closes the PTY, hangs up on p2pool)
 				// Wait to get the exit status
 				let exit_status = match child_pty.lock().unwrap().wait() {
@@ -505,22 +539,11 @@ impl Helper {
 					_ => "Unknown Error",
 				};
 				let uptime = HumanTime::into_human(start.elapsed());
-				info!("P2Pool | Stopped ... Uptime was: [{}], Exit status: [{}]", uptime, exit_status);
+				info!("P2Pool Watchdog | Stopped ... Uptime was: [{}], Exit status: [{}]", uptime, exit_status);
 				// This is written directly into the GUI API, because sometimes the 900ms event loop can't catch it.
 				writeln!(gui_api.lock().unwrap().output, "{}\nP2Pool stopped | Uptime: [{}] | Exit status: [{}]\n{}\n\n\n\n", HORI_CONSOLE, uptime, exit_status, HORI_CONSOLE);
 				process.lock().unwrap().state = ProcessState::Waiting;
-				break
-			// Check if the process is secretly died without us knowing :)
-			} else if let Ok(Some(code)) = child_pty.lock().unwrap().try_wait() {
-				let exit_status = match code.success() {
-					true  => { process.lock().unwrap().state = ProcessState::Dead; "Successful" },
-					false => { process.lock().unwrap().state = ProcessState::Failed; "Failed" },
-				};
-				let uptime = HumanTime::into_human(start.elapsed());
-				info!("P2Pool | Stopped ... Uptime was: [{}], Exit status: [{}]", uptime, exit_status);
-				// This is written directly into the GUI, because sometimes the 900ms event loop can't catch it.
-				writeln!(gui_api.lock().unwrap().output, "{}\nP2Pool stopped | Uptime: [{}] | Exit status: [{}]\n{}\n\n\n\n", HORI_CONSOLE, uptime, exit_status, HORI_CONSOLE);
-				process.lock().unwrap().signal = ProcessSignal::None;
+				debug!("P2Pool Watchdog | Restart SIGNAL done, breaking");
 				break
 			}
 
@@ -529,15 +552,18 @@ impl Helper {
 			if !lock.input.is_empty() {
 				let input = std::mem::take(&mut lock.input);
 				for line in input {
+					debug!("P2Pool Watchdog | User input not empty, writing to STDIN: [{}]", line);
 					writeln!(lock.stdin.as_mut().unwrap(), "{}", line);
 				}
 			}
 			drop(lock);
 
 			// Always update from output
+			debug!("P2Pool Watchdog | Starting [update_from_output()]");
 			PubP2poolApi::update_from_output(&pub_api, &output_full, &output_buf, start.elapsed(), &regex);
 
 			// Read API file into string
+			debug!("P2Pool Watchdog | Attempting API file read");
 			if let Ok(string) = PrivP2poolApi::read_p2pool_api(&path) {
 				// Deserialize
 				if let Ok(s) = PrivP2poolApi::str_to_priv_p2pool_api(&string) {
@@ -547,17 +573,24 @@ impl Helper {
 			}
 
 			// Check if logs need resetting
+			debug!("P2Pool Watchdog | Attempting log reset check");
 			Self::check_reset_output_full(&output_full, ProcessName::P2pool);
 			Self::check_reset_gui_p2pool_output(&gui_api);
 
 			// Sleep (only if 900ms hasn't passed)
 			let elapsed = now.elapsed().as_millis();
 			// Since logic goes off if less than 1000, casting should be safe
-			if elapsed < 900 { std::thread::sleep(std::time::Duration::from_millis((900-elapsed) as u64)); }
+			if elapsed < 900 {
+				let sleep = (900-elapsed) as u64;
+				debug!("P2Pool Watchdog | END OF LOOP - Sleeping for [{}]ms...", sleep);
+				std::thread::sleep(std::time::Duration::from_millis(sleep));
+			} else {
+				debug!("P2Pool Watchdog | END OF LOOP - Not sleeping!");
+			}
 		}
 
 		// 5. If loop broke, we must be done here.
-		info!("P2Pool | Watchdog thread exiting... Goodbye!");
+		info!("P2Pool Watchdog | Watchdog thread exiting... Goodbye!");
 	}
 
 	//---------------------------------------------------------------------------------------------------- XMRig specific, most functions are very similar to P2Pool's
@@ -620,6 +653,7 @@ impl Helper {
 				thread::sleep(SECOND);
 			}
 			// Ok, process is not alive, start the new one!
+			info!("XMRig | Old process seems dead, starting new one!");
 			Self::start_xmrig(&helper, &state, &path, sudo);
 		});
 		info!("XMRig | Restart ... OK");
@@ -745,6 +779,7 @@ impl Helper {
 	#[tokio::main]
 	async fn spawn_xmrig_watchdog(process: Arc<Mutex<Process>>, gui_api: Arc<Mutex<PubXmrigApi>>, pub_api: Arc<Mutex<PubXmrigApi>>, priv_api: Arc<Mutex<PrivXmrigApi>>, args: Vec<String>, mut path: std::path::PathBuf, sudo: Arc<Mutex<SudoState>>, api_ip_port: String) {
 		// 1a. Create PTY
+		debug!("XMRig | Creating PTY...");
 		let pty = portable_pty::native_pty_system();
 		let mut pair = pty.openpty(portable_pty::PtySize {
 			rows: 100,
@@ -753,15 +788,18 @@ impl Helper {
 			pixel_height: 0,
 		}).unwrap();
 		// 1b. Create command
+		debug!("XMRig | Creating command...");
 		#[cfg(target_os = "windows")]
 		let cmd = Self::create_xmrig_cmd_windows(args, path);
 		#[cfg(target_family = "unix")]
 		let cmd = Self::create_xmrig_cmd_unix(args, path);
 		// 1c. Create child
+		debug!("XMRig | Creating child...");
 		let child_pty = Arc::new(Mutex::new(pair.slave.spawn_command(cmd).unwrap()));
 
 		// 2. Input [sudo] pass, wipe, then drop.
 		if cfg!(unix) {
+			debug!("XMRig | Inputting [sudo] and wiping...");
 			// 1d. Sleep to wait for [sudo]'s non-echo prompt (on Unix).
 			// this prevents users pass from showing up in the STDOUT.
 			std::thread::sleep(std::time::Duration::from_secs(3));
@@ -770,6 +808,7 @@ impl Helper {
 		}
 
         // 3. Set process state
+		debug!("XMRig | Setting process state...");
         let mut lock = process.lock().unwrap();
         lock.state = ProcessState::Alive;
         lock.signal = ProcessSignal::None;
@@ -780,6 +819,7 @@ impl Helper {
 		drop(lock);
 
 		// 4. Spawn PTY read thread
+		debug!("XMRig | Spawning PTY read thread...");
 		let output_full = Arc::clone(&process.lock().unwrap().output_full);
 		let output_buf = Arc::clone(&process.lock().unwrap().output_buf);
 		thread::spawn(move || {
@@ -796,9 +836,11 @@ impl Helper {
 		loop {
 			// Set timer
 			let now = Instant::now();
+			debug!("XMRig Watchdog | ----------- Start of loop -----------");
 
 			// Check if the process secretly died without us knowing :)
 			if let Ok(Some(code)) = child_pty.lock().unwrap().try_wait() {
+				debug!("XMRig Watchdog | Process secretly died on us! Getting exit status...");
 				let exit_status = match code.success() {
 					true  => { process.lock().unwrap().state = ProcessState::Dead; "Successful" },
 					false => { process.lock().unwrap().state = ProcessState::Failed; "Failed" },
@@ -807,12 +849,14 @@ impl Helper {
 				info!("XMRig | Stopped ... Uptime was: [{}], Exit status: [{}]", uptime, exit_status);
 				writeln!(gui_api.lock().unwrap().output, "{}\nXMRig stopped | Uptime: [{}] | Exit status: [{}]\n{}\n\n\n\n", HORI_CONSOLE, uptime, exit_status, HORI_CONSOLE);
 				process.lock().unwrap().signal = ProcessSignal::None;
+				debug!("XMRig Watchdog | Secret dead process reap OK, breaking");
 				break
 			}
 
 			// Stop on [Stop/Restart] SIGNAL
 			let signal = process.lock().unwrap().signal;
 			if signal == ProcessSignal::Stop || signal == ProcessSignal::Restart  {
+				debug!("XMRig Watchdog | Stop/Restart SIGNAL caught");
 				// macOS requires [sudo] again to kill [XMRig]
 				if cfg!(target_os = "macos") {
 					// If we're at this point, that means the user has
@@ -851,6 +895,7 @@ impl Helper {
 					ProcessSignal::Restart => process.state = ProcessState::Waiting,
 					_ => (),
 				}
+				debug!("XMRig Watchdog | Stop/Restart SIGNAL done, breaking");
 				break
 			}
 
@@ -859,33 +904,44 @@ impl Helper {
 			if !lock.input.is_empty() {
 				let input = std::mem::take(&mut lock.input);
 				for line in input {
+					debug!("XMRig Watchdog | User input not empty, writing to STDIN: [{}]", line);
 					writeln!(lock.stdin.as_mut().unwrap(), "{}", line);
 				}
 			}
 			drop(lock);
 
 			// Always update from output
+			debug!("XMRig Watchdog | Starting [update_from_output()]");
 			PubXmrigApi::update_from_output(&pub_api, &output_buf, start.elapsed());
 
 			// Send an HTTP API request
+			debug!("XMRig Watchdog | Attempting HTTP API request...");
 			if let Ok(priv_api) = PrivXmrigApi::request_xmrig_api(client.clone(), &api_ip_port).await {
+				debug!("XMRig Watchdog | HTTP API request OK, attempting [update_from_priv()]");
 				PubXmrigApi::update_from_priv(&pub_api, priv_api);
 			} else {
-				warn!("XMRig | Could not send HTTP API request to: {}", api_ip_port);
+				warn!("XMRig Watchdog | Could not send HTTP API request to: {}", api_ip_port);
 			}
 
 			// Check if logs need resetting
+			debug!("XMRig Watchdog | Attempting log reset check");
 			Self::check_reset_output_full(&output_full, ProcessName::Xmrig);
 			Self::check_reset_gui_xmrig_output(&gui_api);
 
 			// Sleep (only if 900ms hasn't passed)
 			let elapsed = now.elapsed().as_millis();
 			// Since logic goes off if less than 1000, casting should be safe
-			if elapsed < 900 { std::thread::sleep(std::time::Duration::from_millis((900-elapsed) as u64)); }
+			if elapsed < 900 {
+				let sleep = (900-elapsed) as u64;
+				debug!("XMRig Watchdog | END OF LOOP - Sleeping for [{}]ms...", sleep);
+				std::thread::sleep(std::time::Duration::from_millis(sleep));
+			} else {
+				debug!("XMRig Watchdog | END OF LOOP - Not sleeping!");
+			}
 		}
 
 		// 5. If loop broke, we must be done here.
-		info!("XMRig | Watchdog thread exiting... Goodbye!");
+		info!("XMRig Watchdog | Watchdog thread exiting... Goodbye!");
 	}
 
 	//---------------------------------------------------------------------------------------------------- The "helper"
@@ -933,38 +989,56 @@ impl Helper {
 		loop {
 		// 1. Loop init timestamp
 		let start = Instant::now();
+		debug!("Helper | ----------- Start of loop -----------");
+
+		//
+		// Ignore the invasive [debug!()] messages on the right side of the code.
+		// The reason why they are there are so that it's extremely easy to track
+		// down the culprit of an [Arc<Mutex>] deadlock. I know, they're ugly.
+		//
 
 		// 2. Lock... EVERYTHING!
-		let mut lock = helper.lock().unwrap();
+		let mut lock = helper.lock().unwrap();                                     debug!("Helper | Locking (1/8) ... [helper]");
 		// Calculate Gupax's uptime always.
 		lock.uptime = HumanTime::into_human(lock.instant.elapsed());
-		let mut gui_api_p2pool = lock.gui_api_p2pool.lock().unwrap();
-		let mut gui_api_xmrig = lock.gui_api_xmrig.lock().unwrap();
-		let mut pub_api_p2pool = lock.pub_api_p2pool.lock().unwrap();
-		let mut pub_api_xmrig = lock.pub_api_xmrig.lock().unwrap();
-		let p2pool = lock.p2pool.lock().unwrap();
-		let xmrig = lock.xmrig.lock().unwrap();
-		let mut lock_pub_sys = pub_sys.lock().unwrap();
+		let mut gui_api_p2pool = lock.gui_api_p2pool.lock().unwrap();              debug!("Helper | Locking (2/8) ... [gui_api_p2pool]");
+		let mut gui_api_xmrig = lock.gui_api_xmrig.lock().unwrap();                debug!("Helper | Locking (3/8) ... [gui_api_xmrig]");
+		let mut pub_api_p2pool = lock.pub_api_p2pool.lock().unwrap();              debug!("Helper | Locking (4/8) ... [pub_api_p2pool]");
+		let mut pub_api_xmrig = lock.pub_api_xmrig.lock().unwrap();                debug!("Helper | Locking (5/8) ... [pub_api_xmrig]");
+		let p2pool = lock.p2pool.lock().unwrap();                                  debug!("Helper | Locking (6/8) ... [p2pool]");
+		let xmrig = lock.xmrig.lock().unwrap();                                    debug!("Helper | Locking (7/8) ... [xmrig]");
+		let mut lock_pub_sys = pub_sys.lock().unwrap();                            debug!("Helper | Locking (8/8) ... [pub_sys]");
 		// If [P2Pool] is alive...
-		if p2pool.is_alive() { PubP2poolApi::combine_gui_pub_api(&mut gui_api_p2pool, &mut pub_api_p2pool); }
+		if p2pool.is_alive() {
+			debug!("Helper | P2Pool is alive! Running [combine_gui_pub_api()]");
+			PubP2poolApi::combine_gui_pub_api(&mut gui_api_p2pool, &mut pub_api_p2pool);
+		} else {
+			debug!("Helper | P2Pool is dead! Skipping...");
+		}
 		// If [XMRig] is alive...
-		if xmrig.is_alive() { PubXmrigApi::combine_gui_pub_api(&mut gui_api_xmrig, &mut pub_api_xmrig); }
+		if xmrig.is_alive() {
+			debug!("Helper | XMRig is alive! Running [combine_gui_pub_api()]");
+			PubXmrigApi::combine_gui_pub_api(&mut gui_api_xmrig, &mut pub_api_xmrig);
+		} else {
+			debug!("Helper | XMRig is dead! Skipping...");
+		}
 
 		// 2. Selectively refresh [sysinfo] for only what we need (better performance).
-		sysinfo.refresh_cpu_specifics(sysinfo_cpu);
-		sysinfo.refresh_processes_specifics(sysinfo_processes);
-		sysinfo.refresh_memory();
+		sysinfo.refresh_cpu_specifics(sysinfo_cpu);                debug!("Helper | Sysinfo refresh (1/3) ... [cpu]");
+		sysinfo.refresh_processes_specifics(sysinfo_processes);    debug!("Helper | Sysinfo refresh (2/3) ... [processes]");
+		sysinfo.refresh_memory();                                  debug!("Helper | Sysinfo refresh (3/3) ... [memory]");
+		debug!("Helper | Sysinfo OK, running [update_pub_sys_from_sysinfo()]");
 		Self::update_pub_sys_from_sysinfo(&sysinfo, &mut lock_pub_sys, &pid, &lock, max_threads);
 
 		// 3. Drop... (almost) EVERYTHING... IN REVERSE!
-		drop(lock_pub_sys);
-		drop(xmrig);
-		drop(p2pool);
-		drop(pub_api_xmrig);
-		drop(pub_api_p2pool);
-		drop(gui_api_xmrig);
-		drop(gui_api_p2pool);
-		drop(lock);
+		drop(lock_pub_sys);     debug!("Helper | Unlocking (1/8) ... [pub_sys]");
+		drop(xmrig);            debug!("Helper | Unlocking (2/8) ... [xmrig]");
+		drop(p2pool);           debug!("Helper | Unlocking (3/8) ... [p2pool]");
+		drop(pub_api_xmrig);    debug!("Helper | Unlocking (4/8) ... [pub_api_xmrig]");
+		drop(pub_api_p2pool);   debug!("Helper | Unlocking (5/8) ... [pub_api_p2pool]");
+		drop(gui_api_xmrig);    debug!("Helper | Unlocking (6/8) ... [gui_api_xmrig]");
+		drop(gui_api_p2pool);   debug!("Helper | Unlocking (7/8) ... [gui_api_p2pool]");
+		drop(lock);             debug!("Helper | Unlocking (8/8) ... [helper]");
 
 		// 4. Calculate if we should sleep or not.
 		// If we should sleep, how long?
@@ -972,7 +1046,11 @@ impl Helper {
 		if elapsed < 1000 {
 			// Casting from u128 to u64 should be safe here, because [elapsed]
 			// is less than 1000, meaning it can fit into a u64 easy.
-			std::thread::sleep(std::time::Duration::from_millis((1000-elapsed) as u64));
+			let sleep = (1000-elapsed) as u64;
+			debug!("Helper | END OF LOOP - Sleeping for [{}]ms...", sleep);
+			std::thread::sleep(std::time::Duration::from_millis(sleep));
+		} else {
+			debug!("Helper | END OF LOOP - Not sleeping!");
 		}
 
 		// 5. End loop
diff --git a/src/main.rs b/src/main.rs
index a6e864b..1828976 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -166,6 +166,7 @@ impl App {
 
 	fn new(now: Instant) -> Self {
 		info!("Initializing App Struct...");
+		debug!("App Init | P2Pool & XMRig processes...");
 		let p2pool = Arc::new(Mutex::new(Process::new(ProcessName::P2pool, String::new(), PathBuf::new())));
 		let xmrig = Arc::new(Mutex::new(Process::new(ProcessName::Xmrig, String::new(), PathBuf::new())));
 		let p2pool_api = Arc::new(Mutex::new(PubP2poolApi::new()));
@@ -173,6 +174,7 @@ impl App {
 		let p2pool_img = Arc::new(Mutex::new(ImgP2pool::new()));
 		let xmrig_img = Arc::new(Mutex::new(ImgXmrig::new()));
 
+		debug!("App Init | Sysinfo...");
 		// We give this to the [Helper] thread.
 		let mut sysinfo = sysinfo::System::new_with_specifics(
 			sysinfo::RefreshKind::new()
@@ -183,6 +185,7 @@ impl App {
 		let pid = sysinfo::get_current_pid().unwrap();
 		let pub_sys = Arc::new(Mutex::new(Sys::new()));
 
+		debug!("App Init | The rest of the [App]...");
 		let mut app = Self {
 			tab: Tab::default(),
 			ping: Arc::new(Mutex::new(Ping::new())),
@@ -232,6 +235,7 @@ impl App {
 			regex: Regexes::new(),
 		};
 		//---------------------------------------------------------------------------------------------------- App init data that *could* panic
+		debug!("App Init | Getting EXE path...");
 		let mut panic = String::new();
 		// Get exe path
 		app.exe = match get_exe() {
@@ -249,6 +253,7 @@ impl App {
 			Err(e) => { panic = format!("get_os_data_path(): {}", e); app.error_state.set(panic.clone(), ErrorFerris::Panic, ErrorButtons::Quit); PathBuf::new() },
 		};
 
+		debug!("App Init | Setting TOML path...");
 		// Set [*.toml] path
 		app.state_path = app.os_data_path.clone();
 		app.state_path.push("state.toml");
@@ -260,9 +265,11 @@ impl App {
 		// Apply arg state
 		// It's not safe to [--reset] if any of the previous variables
 		// are unset (null path), so make sure we just abort if the [panic] String contains something.
+		debug!("App Init | Applying argument state...");
 		let mut app = parse_args(app, panic);
 
 		// Read disk state
+		debug!("App Init | Reading disk state...");
 		use TomlError::*;
 		app.state = match State::get(&app.state_path) {
 			Ok(toml) => toml,
@@ -281,6 +288,7 @@ impl App {
 		};
 		app.og = Arc::new(Mutex::new(app.state.clone()));
 		// Read node list
+		debug!("App Init | Reading node list...");
 		app.og_node_vec = match Node::get(&app.node_path) {
 			Ok(toml) => toml,
 			Err(err) => {
@@ -297,6 +305,7 @@ impl App {
 			},
 		};
 		// Read pool list
+		debug!("App Init | Reading pool list...");
 		app.og_pool_vec = match Pool::get(&app.pool_path) {
 			Ok(toml) => toml,
 			Err(err) => {
@@ -317,6 +326,7 @@ impl App {
 		//----------------------------------------------------------------------------------------------------
 		let mut og = app.og.lock().unwrap(); // Lock [og]
 		// Handle max threads
+		debug!("App Init | Handling max thread overflow...");
 		og.xmrig.max_threads = app.max_threads;
 		let current = og.xmrig.current_threads;
 		let max = og.xmrig.max_threads;
@@ -324,6 +334,7 @@ impl App {
 			og.xmrig.current_threads = max;
 		}
 		// Handle [node_vec] overflow
+		debug!("App Init | Handling [node_vec] overflow");
 		if og.p2pool.selected_index > app.og_node_vec.len() {
 			warn!("App | Overflowing manual node index [{} > {}], resetting to 1", og.p2pool.selected_index, app.og_node_vec.len());
 			let (name, node) = app.og_node_vec[0].clone();
@@ -339,6 +350,7 @@ impl App {
 			app.state.p2pool.selected_zmq = node.zmq;
 		}
 		// Handle [pool_vec] overflow
+		debug!("App Init | Handling [pool_vec] overflow...");
 		if og.xmrig.selected_index > app.og_pool_vec.len() {
 			warn!("App | Overflowing manual pool index [{} > {}], resetting to 1", og.xmrig.selected_index, app.og_pool_vec.len());
 			let (name, pool) = app.og_pool_vec[0].clone();
@@ -351,16 +363,24 @@ impl App {
 			app.state.xmrig.selected_ip = pool.ip;
 			app.state.xmrig.selected_port = pool.port;
 		}
+
 		// Apply TOML values to [Update]
+		debug!("App Init | Applying TOML values to [Update]...");
 		let p2pool_path = og.gupax.absolute_p2pool_path.clone();
 		let xmrig_path = og.gupax.absolute_xmrig_path.clone();
 		let tor = og.gupax.update_via_tor;
 		app.update = Arc::new(Mutex::new(Update::new(app.exe.clone(), p2pool_path, xmrig_path, tor)));
+
+
+		debug!("App Init | Setting state Gupax version...");
 		// Set state version as compiled in version
 		og.version.lock().unwrap().gupax = GUPAX_VERSION.to_string();
 		app.state.version.lock().unwrap().gupax = GUPAX_VERSION.to_string();
+
+		debug!("App Init | Setting saved [Tab]...");
 		// Set saved [Tab]
 		app.tab = app.state.gupax.tab;
+
 		drop(og); // Unlock [og]
 		info!("App ... OK");
 
@@ -370,6 +390,7 @@ impl App {
 		info!("Helper ... OK");
 
 		// Check for privilege. Should be Admin on [Windows] and NOT root on Unix.
+		debug!("App Init | Checking for privilege level...");
 		#[cfg(target_os = "windows")]
 		if is_elevated::is_elevated() {
 			app.admin = true;
@@ -835,6 +856,7 @@ impl eframe::App for App {
 		// *-------*
 		// | DEBUG |
 		// *-------*
+		debug!("App | ----------- Start of [update()] -----------");
 
 		// If [F11] was pressed, reverse [fullscreen] bool
         if ctx.input_mut().consume_key(Modifiers::NONE, Key::F11) {
@@ -843,10 +865,12 @@ impl eframe::App for App {
         }
 
 		// Refresh AT LEAST once a second
+		debug!("App | Refreshing frame once per second");
 		ctx.request_repaint_after(SECOND);
 
 		// This sets the top level Ui dimensions.
 		// Used as a reference for other uis.
+		debug!("App | Setting width/height");
 		CentralPanel::default().show(ctx, |ui| {
 			let available_width = ui.available_width();
 			if self.width != available_width {
@@ -863,6 +887,7 @@ impl eframe::App for App {
 		// while the user was readjusting the frame. It's a pretty heavy operation and looks
 		// buggy when calling it that many times. Looking for a [must_resize] in addtion to
 		// checking if the user is hovering over the app means that we only have call it once.
+		debug!("App | Checking if we need to resize");
 		if self.must_resize && ctx.is_pointer_over_area() {
 			self.resizing = true;
 			self.must_resize = false;
@@ -899,6 +924,7 @@ impl eframe::App for App {
 		}
 
 		// If there's an error, display [ErrorState] on the whole screen until user responds
+		debug!("App | Checking if there is an error in [ErrorState]");
 		if self.error_state.error {
 			CentralPanel::default().show(ctx, |ui| {
 			ui.vertical_centered(|ui| {
@@ -1058,6 +1084,7 @@ impl eframe::App for App {
 		// The struct fields are compared directly because [Version]
 		// contains Arc<Mutex>'s that cannot be compared easily.
 		// They don't need to be compared anyway.
+		debug!("App | Checking diff between [og] & [state]");
 		let og = self.og.lock().unwrap();
 		if og.gupax != self.state.gupax || og.p2pool != self.state.p2pool || og.xmrig != self.state.xmrig || self.og_node_vec != self.node_vec {
 			self.diff = true;
@@ -1067,6 +1094,7 @@ impl eframe::App for App {
 		drop(og);
 
 		// Top: Tabs
+		debug!("App | Rendering TOP tabs");
 		TopBottomPanel::top("top").show(ctx, |ui| {
 			let width = (self.width - (SPACE*10.0))/5.0;
 			let height = self.height/12.0;
@@ -1091,6 +1119,7 @@ impl eframe::App for App {
 		});
 
 		// Bottom: app info + state/process buttons
+		debug!("App | Rendering BOTTOM bar");
 		TopBottomPanel::bottom("bottom").show(ctx, |ui| {
 			let height = self.height/20.0;
 			ui.style_mut().override_text_style = Some(Name("Bottom".into()));
@@ -1308,6 +1337,7 @@ impl eframe::App for App {
 		});
 
 		// Middle panel, contents of the [Tab]
+		debug!("App | Rendering CENTRAL_PANEL (tab contents)");
 		CentralPanel::default().show(ctx, |ui| {
 			// This sets the Ui dimensions after Top/Bottom are filled
 			self.width = ui.available_width();
@@ -1315,6 +1345,7 @@ impl eframe::App for App {
 			ui.style_mut().override_text_style = Some(TextStyle::Body);
 			match self.tab {
 				Tab::About => {
+					debug!("App | Entering [About] Tab");
 					ui.add_space(10.0);
 					ui.vertical_centered(|ui| {
 						// Display [Gupax] banner at max, 1/4 the available length
@@ -1336,15 +1367,19 @@ impl eframe::App for App {
 					});
 				}
 				Tab::Status => {
+					debug!("App | Entering [Status] Tab");
 					Status::show(&self.pub_sys, &self.p2pool_api, &self.xmrig_api, &self.p2pool_img, &self.xmrig_img, self.p2pool.lock().unwrap().is_alive(), self.xmrig.lock().unwrap().is_alive(), self.width, self.height, ctx, ui);
 				}
 				Tab::Gupax => {
+					debug!("App | Entering [Gupax] Tab");
 					Gupax::show(&mut self.state.gupax, &self.og, &self.state_path, &self.update, &self.file_window, &mut self.error_state, &self.restart, self.width, self.height, frame, ctx, ui);
 				}
 				Tab::P2pool => {
+					debug!("App | Entering [P2Pool] Tab");
 					P2pool::show(&mut self.state.p2pool, &mut self.node_vec, &self.og, &self.ping, &self.regex, &self.p2pool, &self.p2pool_api, &mut self.p2pool_console, self.width, self.height, ctx, ui);
 				}
 				Tab::Xmrig => {
+					debug!("App | Entering [XMRig] Tab");
 					Xmrig::show(&mut self.state.xmrig, &mut self.pool_vec, &self.regex, &self.xmrig, &self.xmrig_api, &mut self.xmrig_console, self.width, self.height, ctx, ui);
 				}
 			}
diff --git a/src/node.rs b/src/node.rs
index 25642f5..c420bc5 100644
--- a/src/node.rs
+++ b/src/node.rs
@@ -213,12 +213,14 @@ impl Ping {
 	//---------------------------------------------------------------------------------------------------- Main Ping function
 	// Intermediate function for spawning thread
 	pub fn spawn_thread(ping: &Arc<Mutex<Self>>) {
+		info!("Spawning ping thread...");
 		let ping = Arc::clone(ping);
 		std::thread::spawn(move|| {
-			info!("Spawning ping thread...");
-			match Self::ping(ping.clone()) {
-				Ok(_) => {
+			let now = Instant::now();
+			match Self::ping(&ping) {
+				Ok(msg) => {
 					info!("Ping ... OK");
+					ping.lock().unwrap().msg = msg;
 					ping.lock().unwrap().pinged = true;
 					ping.lock().unwrap().auto_selected = false;
 				},
@@ -228,6 +230,7 @@ impl Ping {
 					ping.lock().unwrap().msg = err.to_string();
 				},
 			}
+			info!("Ping ... Took [{}] seconds...", now.elapsed().as_secs_f32());
 			ping.lock().unwrap().pinging = false;
 		});
 	}
@@ -250,9 +253,10 @@ impl Ping {
 	// timeout = BLACK
 	// default = GRAY
 	#[tokio::main]
-	pub async fn ping(ping: Arc<Mutex<Self>>) -> Result<(), anyhow::Error> {
+	pub async fn ping(ping: &Arc<Mutex<Self>>) -> Result<String, anyhow::Error> {
 		// Timer
 		let now = Instant::now();
+		let ping = Arc::clone(ping);
 
 		// Start ping
 		ping.lock().unwrap().pinging = true;
@@ -268,8 +272,8 @@ impl Ping {
 		// Random User Agent
 		let rand_user_agent = crate::Pkg::get_user_agent();
 		// Handle vector
-		let mut handles = vec![];
-		let node_vec = Arc::new(Mutex::new(Vec::new()));
+		let mut handles = Vec::with_capacity(NODE_IPS.len());
+		let node_vec = Arc::new(Mutex::new(Vec::with_capacity(NODE_IPS.len())));
 
 		for ip in NODE_IPS {
 			let client = client.clone();
@@ -288,18 +292,19 @@ impl Ping {
 		for handle in handles {
 			handle.await?;
 		}
-		let node_vec = node_vec.lock().unwrap().clone();
 
-		let info = format!("Fastest node: {}ms ... {} @ {}", node_vec[0].ms, node_vec[0].id, node_vec[0].ip);
-		info!("Ping | {}", info);
-		info!("Ping | Took [{}] seconds...", now.elapsed().as_secs_f32());
+		let node_vec = std::mem::take(&mut *node_vec.lock().unwrap());
+		let fastest_info = format!("Fastest node: {}ms ... {} @ {}", node_vec[0].ms, node_vec[0].id, node_vec[0].ip);
+
+		let info = format!("Cleaning up connections");
+		info!("Ping | {}...", info);
 		let mut ping = ping.lock().unwrap();
 			ping.fastest = node_vec[0].id;
 			ping.nodes = node_vec;
 			ping.prog = 100.0;
 			ping.msg = info;
 			drop(ping);
-		Ok(())
+		Ok(fastest_info)
 	}
 
 	async fn response(client: Client<HttpConnector>, request: Request<Body>, ip: &'static str, ping: Arc<Mutex<Self>>, percent: f32, node_vec: Arc<Mutex<Vec<NodeData>>>) {
diff --git a/src/p2pool.rs b/src/p2pool.rs
index c9dc667..7448aed 100644
--- a/src/p2pool.rs
+++ b/src/p2pool.rs
@@ -35,6 +35,7 @@ impl P2pool {
 	pub fn show(&mut self, node_vec: &mut Vec<(String, Node)>, og: &Arc<Mutex<State>>, ping: &Arc<Mutex<Ping>>, regex: &Regexes, process: &Arc<Mutex<Process>>, api: &Arc<Mutex<PubP2poolApi>>, buffer: &mut String, width: f32, height: f32, ctx: &egui::Context, ui: &mut egui::Ui) {
 	let text_edit = height / 25.0;
 	//---------------------------------------------------------------------------------------------------- [Simple] Console
+	debug!("P2Pool Tab | Rendering [Console]");
 	ui.group(|ui| {
 	if self.simple {
 		let height = height / 2.4;
@@ -71,6 +72,7 @@ impl P2pool {
 
 	//---------------------------------------------------------------------------------------------------- Args
 	if !self.simple {
+		debug!("P2Pool Tab | Rendering [Arguments]");
 		ui.group(|ui| { ui.horizontal(|ui| {
 			let width = (width/10.0) - SPACE;
 			ui.style_mut().override_text_style = Some(Monospace);
@@ -82,6 +84,7 @@ impl P2pool {
 	}
 
 	//---------------------------------------------------------------------------------------------------- Address
+	debug!("P2Pool Tab | Rendering [Address]");
 	ui.group(|ui| {
 		let width = width - SPACE;
 		ui.spacing_mut().text_edit_width = (width)-(SPACE*3.0);
@@ -117,6 +120,7 @@ impl P2pool {
 		// saves me the hassle of wrapping [state: State] completely
 		// and [.lock().unwrap()]ing it everywhere.
 		// Two atomic bools = enough to represent this data
+		debug!("P2Pool Tab | Running [auto-select] check");
 		if self.auto_select {
 			let mut ping = ping.lock().unwrap();
 			// If we haven't auto_selected yet, auto-select and turn it off
@@ -129,6 +133,7 @@ impl P2pool {
 
 		ui.vertical(|ui| {
 		ui.horizontal(|ui| {
+			debug!("P2Pool Tab | Rendering [Ping List]");
 			// [Ping List]
 			let id = self.node;
 			let ip = enum_to_ip(id);
@@ -143,6 +148,7 @@ impl P2pool {
 					}
 				}
 			}
+			debug!("P2Pool Tab | Rendering [ComboBox] of Community Nodes");
 			let text = RichText::new(format!(" ⏺ {}ms | {} | {}", ms, id, ip)).color(color);
 			ComboBox::from_id_source("community_nodes").selected_text(RichText::text_style(text, Monospace)).show_ui(ui, |ui| {
 				for data in ping.lock().unwrap().nodes.iter() {
@@ -156,6 +162,7 @@ impl P2pool {
 
 		ui.add_space(5.0);
 
+		debug!("P2Pool Tab | Rendering [Select fastest ... Ping] buttons");
 		ui.horizontal(|ui| {
 		let width = (width/2.0)-4.0;
 		// [Select fastest node]
@@ -189,15 +196,11 @@ impl P2pool {
 		});
 		});
 
+		debug!("P2Pool Tab | Rendering [Auto-*] buttons");
 		ui.group(|ui| {
 		ui.horizontal(|ui| {
 			let width = (width/2.0)-(SPACE*1.75);
 			// [Auto-node] + [Auto-select]
-//			let mut style = (*ctx.style()).clone();
-//			style.spacing.icon_width_inner = width / 16.0;
-//			style.spacing.icon_width = width / 6.0;
-//			style.spacing.icon_spacing = 20.0;
-//			ctx.set_style(style);
 			ui.add_sized([width, height], Checkbox::new(&mut self.auto_select, "Auto-select")).on_hover_text(P2POOL_AUTO_SELECT);
 			ui.separator();
 			ui.add_sized([width, height], Checkbox::new(&mut self.auto_node, "Auto-node")).on_hover_text(P2POOL_AUTO_NODE);
@@ -205,6 +208,7 @@ impl P2pool {
 
 	//---------------------------------------------------------------------------------------------------- Advanced
 	} else {
+		debug!("P2Pool Tab | Rendering [Node List] elements");
 		let mut incorrect_input = false; // This will disable [Add/Delete] on bad input
 		// [Monero node IP/RPC/ZMQ]
 		ui.horizontal(|ui| {
@@ -302,6 +306,7 @@ impl P2pool {
 			ui.spacing_mut().slider_width = width - 8.0;
 			ui.spacing_mut().icon_width = width / 25.0;
 			// [Ping List]
+			debug!("P2Pool Tab | Rendering [Node List]");
 			let text = RichText::new(format!("{}. {}", self.selected_index+1, self.selected_name));
 			ComboBox::from_id_source("manual_nodes").selected_text(RichText::text_style(text, Monospace)).show_ui(ui, |ui| {
 				let mut n = 0;
@@ -416,6 +421,7 @@ impl P2pool {
 		});
 		ui.add_space(5.0);
 
+		debug!("P2Pool Tab | Rendering [Main/Mini/Peers/Log] elements");
 		// [Main/Mini]
 		ui.horizontal(|ui| {
 		let height = height/4.0;
diff --git a/src/status.rs b/src/status.rs
index be2d4fc..fda65bf 100644
--- a/src/status.rs
+++ b/src/status.rs
@@ -25,6 +25,7 @@ use crate::{
 	Sys,
 };
 use std::sync::{Arc,Mutex};
+use log::*;
 use egui::{
 	containers::*,
 	Label,RichText,TextStyle
@@ -42,6 +43,7 @@ pub fn show(sys: &Arc<Mutex<Sys>>, p2pool_api: &Arc<Mutex<PubP2poolApi>>, xmrig_
 	ui.horizontal(|ui| {
 	// [Gupax]
 	ui.group(|ui| { ui.vertical(|ui| {
+		debug!("Status | Rendering [Gupax]");
 		ui.set_min_height(min_height);
 		ui.add_sized([width, height*2.0], Label::new(RichText::new("[Gupax]").color(LIGHT_GRAY).text_style(TextStyle::Name("MonospaceLarge".into())))).on_hover_text("Gupax is online");
 		let sys = sys.lock().unwrap();
@@ -61,6 +63,7 @@ pub fn show(sys: &Arc<Mutex<Sys>>, p2pool_api: &Arc<Mutex<PubP2poolApi>>, xmrig_
 	})});
 	// [P2Pool]
 	ui.group(|ui| { ui.vertical(|ui| {
+		debug!("Status Tab | Rendering [P2Pool]");
 		ui.set_enabled(p2pool_online);
 		ui.set_min_height(min_height);
 		ui.add_sized([width, height*2.0], Label::new(RichText::new("[P2Pool]").color(LIGHT_GRAY).text_style(TextStyle::Name("MonospaceLarge".into())))).on_hover_text("P2Pool is online").on_disabled_hover_text("P2Pool is offline");
@@ -85,6 +88,7 @@ pub fn show(sys: &Arc<Mutex<Sys>>, p2pool_api: &Arc<Mutex<PubP2poolApi>>, xmrig_
 	})});
 	// [XMRig]
 	ui.group(|ui| { ui.vertical(|ui| {
+		debug!("Status Tab | Rendering [XMRig]");
 		ui.set_enabled(xmrig_online);
 		ui.set_min_height(min_height);
 		ui.add_sized([width, height*2.0], Label::new(RichText::new("[XMRig]").color(LIGHT_GRAY).text_style(TextStyle::Name("MonospaceLarge".into())))).on_hover_text("XMRig is online").on_disabled_hover_text("XMRig is offline");
diff --git a/src/xmrig.rs b/src/xmrig.rs
index 0e26d6b..d133547 100644
--- a/src/xmrig.rs
+++ b/src/xmrig.rs
@@ -36,6 +36,7 @@ impl Xmrig {
 	pub fn show(&mut self, pool_vec: &mut Vec<(String, Pool)>, regex: &Regexes, process: &Arc<Mutex<Process>>, api: &Arc<Mutex<PubXmrigApi>>, buffer: &mut String, width: f32, height: f32, ctx: &egui::Context, ui: &mut egui::Ui) {
 	let text_edit = height / 25.0;
 	//---------------------------------------------------------------------------------------------------- [Simple] Console
+	debug!("XMRig Tab | Rendering [Console]");
 	ui.group(|ui| {
 	if self.simple {
 		let height = height / 1.5;
@@ -70,8 +71,9 @@ impl Xmrig {
 	}
 	});
 
-	//---------------------------------------------------------------------------------------------------- Config
+	//---------------------------------------------------------------------------------------------------- Arguments
 	if !self.simple {
+		debug!("XMRig Tab | Rendering [Arguments]");
 		ui.group(|ui| { ui.horizontal(|ui| {
 			let width = (width/10.0) - SPACE;
 			ui.style_mut().override_text_style = Some(Monospace);
@@ -81,6 +83,7 @@ impl Xmrig {
 		})});
 		ui.set_enabled(self.arguments.is_empty());
 	//---------------------------------------------------------------------------------------------------- Address
+		debug!("XMRig Tab | Rendering [Address]");
 		ui.group(|ui| {
 			let width = width - SPACE;
 			ui.spacing_mut().text_edit_width = (width)-(SPACE*3.0);
@@ -106,6 +109,7 @@ impl Xmrig {
 
 	//---------------------------------------------------------------------------------------------------- Threads
 	if self.simple { ui.add_space(SPACE); }
+	debug!("XMRig Tab | Rendering [Threads]");
 	ui.vertical(|ui| {
 		let width = width/10.0;
 		ui.spacing_mut().icon_width = width / 25.0;
@@ -129,7 +133,8 @@ impl Xmrig {
 
 //		});
 	} else {
-		let _height = height / 10.0;
+		debug!("XMRig Tab | Rendering [Pool List] elements");
+//		let _height = height / 10.0;
 		let width = ui.available_width() - 10.0;
 		let mut incorrect_input = false; // This will disable [Add/Delete] on bad input
 		// [Pool IP/Port]
@@ -226,7 +231,8 @@ impl Xmrig {
 			// [Manual node selection]
 			ui.spacing_mut().slider_width = width - 8.0;
 			ui.spacing_mut().icon_width = width / 25.0;
-			// [Ping List]
+			// [Node List]
+			debug!("XMRig Tab | Rendering [Node List] ComboBox");
 			let text = RichText::new(format!("{}. {}", self.selected_index+1, self.selected_name));
 			ComboBox::from_id_source("manual_pool").selected_text(RichText::text_style(text, Monospace)).show_ui(ui, |ui| {
 				let mut n = 0;
@@ -345,7 +351,8 @@ impl Xmrig {
 		});
 		ui.add_space(5.0);
 
-		// [HTTP API IP/Port] + [TLS + Keepalive]
+		debug!("XMRig Tab | Rendering [API] TextEdits");
+		// [HTTP API IP/Port]
 		ui.group(|ui| { ui.horizontal(|ui| {
 		ui.vertical(|ui| {
 			let width = width/10.0;
@@ -396,6 +403,7 @@ impl Xmrig {
 
 		ui.separator();
 
+		debug!("XMRig Tab | Rendering [TLS/Keepalive] buttons");
 		ui.vertical(|ui| {
 			// TLS/Keepalive
 			ui.horizontal(|ui| {