122 lines
3.1 KiB
Go
122 lines
3.1 KiB
Go
package inspur
|
|
|
|
import (
|
|
"regexp"
|
|
"strings"
|
|
"time"
|
|
|
|
"git.mchus.pro/mchus/logpile/internal/models"
|
|
)
|
|
|
|
// ParseIDLLog parses IDL-style entries for BMC alarms.
|
|
// Works for both plain idl.log lines and JSON structured logs (idl_json/run_json)
|
|
// where MESSAGE/LOG2_FMTMSG contains:
|
|
// |timestamp|component|type|severity|eventID|description|
|
|
func ParseIDLLog(content []byte) []models.Event {
|
|
var events []models.Event
|
|
|
|
// Pattern to match CommerDiagnose log entries
|
|
// Example: |2025-12-02T17:54:27+08:00|MEMORY|Assert|Warning|0C180401|CPU1_C4D0 Memory Device Disabled...|
|
|
re := regexp.MustCompile(`\|(\d{4}-\d{2}-\d{2}T[\d:]+[+-]\d{2}:\d{2})\|([^|]+)\|([^|]+)\|([^|]+)\|([^|]+)\|([^|]+)\|`)
|
|
|
|
lines := strings.Split(string(content), "\n")
|
|
seenEvents := make(map[string]bool) // Deduplicate events
|
|
|
|
for _, line := range lines {
|
|
matches := re.FindStringSubmatch(line)
|
|
if matches == nil {
|
|
continue
|
|
}
|
|
|
|
timestamp := matches[1]
|
|
component := matches[2]
|
|
eventType := matches[3]
|
|
severityStr := matches[4]
|
|
eventID := matches[5]
|
|
description := matches[6]
|
|
|
|
// Parse timestamp
|
|
ts, err := time.Parse("2006-01-02T15:04:05-07:00", timestamp)
|
|
if err != nil {
|
|
ts = time.Now()
|
|
}
|
|
|
|
// Map severity
|
|
severity := mapIDLSeverity(severityStr)
|
|
|
|
// Clean up description
|
|
description = cleanDescription(description)
|
|
|
|
// Create unique key for deduplication
|
|
eventKey := eventID + "|" + description
|
|
if seenEvents[eventKey] {
|
|
continue
|
|
}
|
|
seenEvents[eventKey] = true
|
|
|
|
// Extract sensor name from description if available
|
|
sensorName := extractSensorName(description, component)
|
|
|
|
events = append(events, models.Event{
|
|
ID: eventID,
|
|
Timestamp: ts,
|
|
Source: component,
|
|
SensorType: strings.ToLower(component),
|
|
SensorName: sensorName,
|
|
EventType: eventType,
|
|
Severity: severity,
|
|
Description: description,
|
|
})
|
|
}
|
|
|
|
return events
|
|
}
|
|
|
|
func mapIDLSeverity(s string) models.Severity {
|
|
switch strings.ToLower(s) {
|
|
case "critical", "error":
|
|
return models.SeverityCritical
|
|
case "warning":
|
|
return models.SeverityWarning
|
|
default:
|
|
return models.SeverityInfo
|
|
}
|
|
}
|
|
|
|
func cleanDescription(desc string) string {
|
|
// Remove trailing " - Assert" or similar
|
|
desc = strings.TrimSuffix(desc, " - Assert")
|
|
desc = strings.TrimSuffix(desc, " - Deassert")
|
|
desc = strings.TrimSpace(desc)
|
|
return desc
|
|
}
|
|
|
|
func extractSensorName(desc, component string) string {
|
|
// Try to extract sensor/device name from description
|
|
// For memory: CPU1_C4D0, CPU1_C4D1, etc.
|
|
if component == "MEMORY" {
|
|
re := regexp.MustCompile(`(CPU\d+_C\d+D\d+)`)
|
|
if matches := re.FindStringSubmatch(desc); matches != nil {
|
|
return matches[1]
|
|
}
|
|
}
|
|
|
|
// For PSU: PSU0, PSU1, etc.
|
|
if component == "PSU" || component == "POWER" {
|
|
re := regexp.MustCompile(`(PSU\d+)`)
|
|
if matches := re.FindStringSubmatch(desc); matches != nil {
|
|
return matches[1]
|
|
}
|
|
}
|
|
|
|
// For temperature sensors
|
|
if component == "TEMPERATURE" || component == "THERMAL" {
|
|
re := regexp.MustCompile(`(\w+_Temp|\w+_DTS)`)
|
|
if matches := re.FindStringSubmatch(desc); matches != nil {
|
|
return matches[1]
|
|
}
|
|
}
|
|
|
|
return component
|
|
}
|