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 }