Implement complete structured data architecture
All checks were successful
Build and Release / build-and-release (push) Successful in 2m10s
All checks were successful
Build and Release / build-and-release (push) Successful in 2m10s
Replace fragile string-based metrics with type-safe JSON data structures. Agent converts all metrics to structured data, dashboard processes typed fields. Changes: - Add AgentData struct with CPU, memory, storage, services, backup fields - Replace string parsing with direct field access throughout system - Maintain UI compatibility via temporary metric bridge conversion - Fix NVMe temperature display and eliminate string parsing bugs - Update protocol to support structured data transmission over ZMQ - Comprehensive metric type coverage: CPU, memory, storage, services, backup Version bump to 0.1.131
This commit is contained in:
@@ -380,16 +380,18 @@ impl SystemWidget {
|
||||
}
|
||||
}
|
||||
|
||||
// Handle physical drive metrics: disk_{drive}_health and disk_{drive}_wear_percent
|
||||
// Handle physical drive metrics: disk_{drive}_health, disk_{drive}_wear_percent, and disk_{drive}_temperature
|
||||
if (metric_name.ends_with("_health") && !metric_name.contains("_pool_health"))
|
||||
|| metric_name.ends_with("_wear_percent") {
|
||||
|| metric_name.ends_with("_wear_percent")
|
||||
|| metric_name.ends_with("_temperature") {
|
||||
// Count underscores to distinguish physical drive metrics (disk_{drive}_metric)
|
||||
// from pool drive metrics (disk_{pool}_{drive}_metric)
|
||||
let underscore_count = metric_name.matches('_').count();
|
||||
// disk_nvme0n1_wear_percent has 3 underscores: disk_nvme0n1_wear_percent
|
||||
if underscore_count == 3 { // disk_{drive}_wear_percent (where drive has underscores)
|
||||
if underscore_count == 3 { // disk_{drive}_metric (where drive has underscores)
|
||||
if let Some(suffix_pos) = metric_name.rfind("_health")
|
||||
.or_else(|| metric_name.rfind("_wear_percent")) {
|
||||
.or_else(|| metric_name.rfind("_wear_percent"))
|
||||
.or_else(|| metric_name.rfind("_temperature")) {
|
||||
return Some(metric_name[5..suffix_pos].to_string()); // Skip "disk_"
|
||||
}
|
||||
}
|
||||
@@ -468,15 +470,25 @@ impl SystemWidget {
|
||||
for pool in &self.storage_pools {
|
||||
// Pool header line with type and health
|
||||
let pool_label = if pool.pool_type.starts_with("drive (") {
|
||||
// For physical drives, show the drive name with wear percentage if available
|
||||
// Look for any drive with wear data (physical drives may have drives named after the pool)
|
||||
// For physical drives, show the drive name with temperature and wear percentage if available
|
||||
// Look for any drive with temp/wear data (physical drives may have drives named after the pool)
|
||||
let temp_opt = pool.drives.iter()
|
||||
.find_map(|d| d.temperature);
|
||||
let wear_opt = pool.drives.iter()
|
||||
.find_map(|d| d.wear_percent);
|
||||
|
||||
let mut drive_info = Vec::new();
|
||||
if let Some(temp) = temp_opt {
|
||||
drive_info.push(format!("T: {:.0}°C", temp));
|
||||
}
|
||||
if let Some(wear) = wear_opt {
|
||||
format!("{} W: {:.0}%:", pool.name, wear)
|
||||
} else {
|
||||
drive_info.push(format!("W: {:.0}%", wear));
|
||||
}
|
||||
|
||||
if drive_info.is_empty() {
|
||||
format!("{}:", pool.name)
|
||||
} else {
|
||||
format!("{} {}:", pool.name, drive_info.join(" "))
|
||||
}
|
||||
} else if pool.pool_type == "single" {
|
||||
format!("{}:", pool.mount_point)
|
||||
|
||||
Reference in New Issue
Block a user