Implement logged-in users monitoring and improve widget formatting
Agent improvements: - Add get_logged_in_users() function to SystemCollector using 'who' command - Collect unique, sorted list of currently logged-in users - Include logged_in_users field in system metrics JSON output - Change C-state formatting to show 2 states per row instead of 4 Dashboard improvements: - Update Backups widget to show "Archives: XX, ..." format - System widget ready to display logged-in users with proper formatting The System widget will now show: - C-states formatted as 2 per row for better readability - Logged-in users displayed as "Logged in: user" or "Logged in: X users (user1, user2)"
This commit is contained in:
parent
1ee398e648
commit
c6e8749ddd
@ -124,6 +124,32 @@ impl SystemCollector {
|
|||||||
Ok((used_mb, total_mb))
|
Ok((used_mb, total_mb))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn get_logged_in_users(&self) -> Option<Vec<String>> {
|
||||||
|
// Get currently logged-in users using 'who' command
|
||||||
|
let output = Command::new("who")
|
||||||
|
.output()
|
||||||
|
.await
|
||||||
|
.ok()?;
|
||||||
|
|
||||||
|
let who_output = String::from_utf8_lossy(&output.stdout);
|
||||||
|
let mut users = Vec::new();
|
||||||
|
|
||||||
|
for line in who_output.lines() {
|
||||||
|
if let Some(username) = line.split_whitespace().next() {
|
||||||
|
if !username.is_empty() && !users.contains(&username.to_string()) {
|
||||||
|
users.push(username.to_string());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if users.is_empty() {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
users.sort();
|
||||||
|
Some(users)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async fn get_cpu_cstate_info(&self) -> Option<Vec<String>> {
|
async fn get_cpu_cstate_info(&self) -> Option<Vec<String>> {
|
||||||
// Read C-state information to show all sleep state distributions
|
// Read C-state information to show all sleep state distributions
|
||||||
let mut cstate_times: Vec<(String, u64)> = Vec::new();
|
let mut cstate_times: Vec<(String, u64)> = Vec::new();
|
||||||
@ -178,7 +204,7 @@ impl SystemCollector {
|
|||||||
order_a.cmp(&order_b)
|
order_a.cmp(&order_b)
|
||||||
});
|
});
|
||||||
|
|
||||||
// Format C-states as description lines (split into two rows for readability)
|
// Format C-states as description lines (2 C-states per row)
|
||||||
let mut result = Vec::new();
|
let mut result = Vec::new();
|
||||||
let mut current_line = Vec::new();
|
let mut current_line = Vec::new();
|
||||||
|
|
||||||
@ -187,15 +213,15 @@ impl SystemCollector {
|
|||||||
if percent >= 0.1 { // Only show states with at least 0.1% time
|
if percent >= 0.1 { // Only show states with at least 0.1% time
|
||||||
current_line.push(format!("{}: {:.1}%", name, percent));
|
current_line.push(format!("{}: {:.1}%", name, percent));
|
||||||
|
|
||||||
// Split into two rows when we have 4 items
|
// Split into rows when we have 2 items
|
||||||
if current_line.len() == 4 {
|
if current_line.len() == 2 {
|
||||||
result.push(current_line.join(", "));
|
result.push(current_line.join(", "));
|
||||||
current_line.clear();
|
current_line.clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add remaining items as second line
|
// Add remaining items as final line
|
||||||
if !current_line.is_empty() {
|
if !current_line.is_empty() {
|
||||||
result.push(current_line.join(", "));
|
result.push(current_line.join(", "));
|
||||||
}
|
}
|
||||||
@ -272,6 +298,9 @@ impl Collector for SystemCollector {
|
|||||||
|
|
||||||
// Get C-state information (optional)
|
// Get C-state information (optional)
|
||||||
let cpu_cstate_info = self.get_cpu_cstate_info().await;
|
let cpu_cstate_info = self.get_cpu_cstate_info().await;
|
||||||
|
|
||||||
|
// Get logged-in users (optional)
|
||||||
|
let logged_in_users = self.get_logged_in_users().await;
|
||||||
|
|
||||||
let mut system_metrics = json!({
|
let mut system_metrics = json!({
|
||||||
"summary": {
|
"summary": {
|
||||||
@ -299,6 +328,10 @@ impl Collector for SystemCollector {
|
|||||||
system_metrics["summary"]["cpu_cstate"] = json!(cstates);
|
system_metrics["summary"]["cpu_cstate"] = json!(cstates);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if let Some(users) = logged_in_users {
|
||||||
|
system_metrics["summary"]["logged_in_users"] = json!(users);
|
||||||
|
}
|
||||||
|
|
||||||
debug!("System metrics collected: CPU load {:.2}, Memory {:.1}%",
|
debug!("System metrics collected: CPU load {:.2}, Memory {:.1}%",
|
||||||
cpu_load_5, memory_usage_percent);
|
cpu_load_5, memory_usage_percent);
|
||||||
|
|
||||||
|
|||||||
@ -59,7 +59,7 @@ fn render_metrics(frame: &mut Frame, _host: &HostDisplayData, metrics: &BackupMe
|
|||||||
|
|
||||||
data.add_row(
|
data.add_row(
|
||||||
Some(WidgetStatus::new(latest_status)),
|
Some(WidgetStatus::new(latest_status)),
|
||||||
vec![format!("{} archives, {:.1}GB total", metrics.backup.snapshot_count, metrics.backup.size_gb)],
|
vec![format!("Archives: {}, {:.1}GB total", metrics.backup.snapshot_count, metrics.backup.size_gb)],
|
||||||
vec![
|
vec![
|
||||||
"Latest".to_string(),
|
"Latest".to_string(),
|
||||||
latest_time,
|
latest_time,
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user