diff --git a/audit/internal/platform/sat_fan_stress.go b/audit/internal/platform/sat_fan_stress.go index 5f5aa76..b86ddee 100644 --- a/audit/internal/platform/sat_fan_stress.go +++ b/audit/internal/platform/sat_fan_stress.go @@ -322,7 +322,9 @@ func sampleFanSpeeds() ([]FanReading, error) { } // parseFanSpeeds parses "ipmitool sdr type Fan" output. -// Line format: "FAN1 | 2400.000 | RPM | ok" +// Handles two formats: +// Old: "FAN1 | 2400.000 | RPM | ok" (value in col[1], unit in col[2]) +// New: "FAN1 | 41h | ok | 29.1 | 4340 RPM" (value+unit combined in last col) func parseFanSpeeds(raw string) []FanReading { var fans []FanReading for _, line := range strings.Split(strings.TrimSpace(raw), "\n") { @@ -330,25 +332,39 @@ func parseFanSpeeds(raw string) []FanReading { if len(parts) < 2 { continue } - unit := "" - if len(parts) >= 3 { - unit = strings.TrimSpace(parts[2]) + name := strings.TrimSpace(parts[0]) + // Find the first field that contains "RPM" (either as a standalone unit or inline) + rpmVal := 0.0 + found := false + for _, p := range parts[1:] { + p = strings.TrimSpace(p) + if !strings.Contains(strings.ToUpper(p), "RPM") { + continue + } + if strings.EqualFold(p, "RPM") { + continue // unit-only column in old format; value is in previous field + } + val, err := parseFanRPMValue(p) + if err == nil { + rpmVal = val + found = true + break + } } - valStr := strings.TrimSpace(parts[1]) - if !strings.EqualFold(unit, "RPM") && !strings.Contains(strings.ToUpper(valStr), "RPM") { + // Old format: unit "RPM" is in col[2], value is in col[1] + if !found && len(parts) >= 3 && strings.EqualFold(strings.TrimSpace(parts[2]), "RPM") { + valStr := strings.TrimSpace(parts[1]) + if !strings.EqualFold(valStr, "na") && !strings.EqualFold(valStr, "disabled") && valStr != "" { + if val, err := parseFanRPMValue(valStr); err == nil { + rpmVal = val + found = true + } + } + } + if !found { continue } - if strings.EqualFold(valStr, "na") || strings.EqualFold(valStr, "disabled") || valStr == "" { - continue - } - val, err := parseFanRPMValue(valStr) - if err != nil { - continue - } - fans = append(fans, FanReading{ - Name: strings.TrimSpace(parts[0]), - RPM: val, - }) + fans = append(fans, FanReading{Name: name, RPM: rpmVal}) } return fans } diff --git a/audit/internal/webui/server.go b/audit/internal/webui/server.go index 7ea24a0..8f163e1 100644 --- a/audit/internal/webui/server.go +++ b/audit/internal/webui/server.go @@ -459,7 +459,7 @@ func (h *handler) handleMetricsChartSVG(w http.ResponseWriter, r *http.Request) } vUtil, l := gr.Util.snapshot() datasets = append(datasets, vUtil) - names = append(names, fmt.Sprintf("GPU %d %%", idx)) + names = append(names, fmt.Sprintf("GPU %d", idx)) if len(labels) == 0 { labels = l } @@ -477,7 +477,7 @@ func (h *handler) handleMetricsChartSVG(w http.ResponseWriter, r *http.Request) } vMem, l := gr.MemUtil.snapshot() datasets = append(datasets, vMem) - names = append(names, fmt.Sprintf("GPU %d %%", idx)) + names = append(names, fmt.Sprintf("GPU %d", idx)) if len(labels) == 0 { labels = l } @@ -495,7 +495,7 @@ func (h *handler) handleMetricsChartSVG(w http.ResponseWriter, r *http.Request) } vPow, l := gr.Power.snapshot() datasets = append(datasets, vPow) - names = append(names, fmt.Sprintf("GPU %d W", idx)) + names = append(names, fmt.Sprintf("GPU %d", idx)) if len(labels) == 0 { labels = l } @@ -513,7 +513,7 @@ func (h *handler) handleMetricsChartSVG(w http.ResponseWriter, r *http.Request) } vTemp, l := gr.Temp.snapshot() datasets = append(datasets, vTemp) - names = append(names, fmt.Sprintf("GPU %d °C", idx)) + names = append(names, fmt.Sprintf("GPU %d", idx)) if len(labels) == 0 { labels = l }