Add LOGPile BMC diagnostic log analyzer
Features: - Modular parser architecture for vendor-specific formats - Inspur/Kaytus parser supporting asset.json, devicefrusdr.log, component.log, idl.log, and syslog files - PCI Vendor/Device ID lookup for hardware identification - Web interface with tabs: Events, Sensors, Config, Serials, Firmware - Server specification summary with component grouping - Export to CSV, JSON, TXT formats - BMC alarm parsing from IDL logs (memory errors, PSU events, etc.) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
89
internal/parser/vendors/inspur/sdr.go
vendored
Normal file
89
internal/parser/vendors/inspur/sdr.go
vendored
Normal file
@@ -0,0 +1,89 @@
|
||||
package inspur
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"git.mchus.pro/mchus/logpile/internal/models"
|
||||
)
|
||||
|
||||
// SDR sensor reading patterns
|
||||
var (
|
||||
sdrLineRegex = regexp.MustCompile(`^(\S+)\s+\|\s+(.+?)\s+\|\s+(\w+)$`)
|
||||
valueRegex = regexp.MustCompile(`^([\d.]+)\s+(.+)$`)
|
||||
)
|
||||
|
||||
// ParseSDR parses BMC SDR (Sensor Data Record) output
|
||||
func ParseSDR(content []byte) []models.SensorReading {
|
||||
var readings []models.SensorReading
|
||||
|
||||
scanner := bufio.NewScanner(strings.NewReader(string(content)))
|
||||
for scanner.Scan() {
|
||||
line := strings.TrimSpace(scanner.Text())
|
||||
if line == "" || strings.HasPrefix(line, "BMC sdr Info:") {
|
||||
continue
|
||||
}
|
||||
|
||||
matches := sdrLineRegex.FindStringSubmatch(line)
|
||||
if matches == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
name := strings.TrimSpace(matches[1])
|
||||
valueStr := strings.TrimSpace(matches[2])
|
||||
status := strings.TrimSpace(matches[3])
|
||||
|
||||
reading := models.SensorReading{
|
||||
Name: name,
|
||||
Status: status,
|
||||
}
|
||||
|
||||
// Parse value and unit
|
||||
if valueStr != "disabled" && valueStr != "no reading" && !strings.HasPrefix(valueStr, "0x") {
|
||||
if vm := valueRegex.FindStringSubmatch(valueStr); vm != nil {
|
||||
if v, err := strconv.ParseFloat(vm[1], 64); err == nil {
|
||||
reading.Value = v
|
||||
reading.Unit = strings.TrimSpace(vm[2])
|
||||
}
|
||||
}
|
||||
} else if strings.HasPrefix(valueStr, "0x") {
|
||||
reading.RawValue = valueStr
|
||||
}
|
||||
|
||||
// Determine sensor type
|
||||
reading.Type = determineSensorType(name)
|
||||
|
||||
readings = append(readings, reading)
|
||||
}
|
||||
|
||||
return readings
|
||||
}
|
||||
|
||||
func determineSensorType(name string) string {
|
||||
nameLower := strings.ToLower(name)
|
||||
|
||||
switch {
|
||||
case strings.Contains(nameLower, "temp"):
|
||||
return "temperature"
|
||||
case strings.Contains(nameLower, "fan") && strings.Contains(nameLower, "speed"):
|
||||
return "fan_speed"
|
||||
case strings.Contains(nameLower, "fan") && strings.Contains(nameLower, "status"):
|
||||
return "fan_status"
|
||||
case strings.HasSuffix(nameLower, "_vin") || strings.HasSuffix(nameLower, "_vout") ||
|
||||
strings.HasSuffix(nameLower, "_v") || strings.Contains(nameLower, "volt"):
|
||||
return "voltage"
|
||||
case strings.Contains(nameLower, "power") || strings.HasSuffix(nameLower, "_pin") ||
|
||||
strings.HasSuffix(nameLower, "_pout") || strings.HasSuffix(nameLower, "_pwr"):
|
||||
return "power"
|
||||
case strings.Contains(nameLower, "psu") && strings.Contains(nameLower, "status"):
|
||||
return "psu_status"
|
||||
case strings.Contains(nameLower, "cpu") && strings.Contains(nameLower, "status"):
|
||||
return "cpu_status"
|
||||
case strings.Contains(nameLower, "hdd") || strings.Contains(nameLower, "nvme"):
|
||||
return "storage_status"
|
||||
default:
|
||||
return "other"
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user