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>
98 lines
2.1 KiB
Go
98 lines
2.1 KiB
Go
package inspur
|
|
|
|
import (
|
|
"bufio"
|
|
"regexp"
|
|
"strings"
|
|
"time"
|
|
|
|
"git.mchus.pro/mchus/logpile/internal/models"
|
|
)
|
|
|
|
var (
|
|
// Syslog format: <priority> timestamp hostname process: message
|
|
syslogRegex = regexp.MustCompile(`^<(\d+)>\s*(\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}[^\s]*)\s+(\S+)\s+(\S+):\s*(.*)$`)
|
|
)
|
|
|
|
// ParseSyslog parses syslog format logs
|
|
func ParseSyslog(content []byte, sourcePath string) []models.Event {
|
|
var events []models.Event
|
|
|
|
// Determine severity from file path
|
|
severity := determineSeverityFromPath(sourcePath)
|
|
|
|
scanner := bufio.NewScanner(strings.NewReader(string(content)))
|
|
lineNum := 0
|
|
|
|
for scanner.Scan() {
|
|
lineNum++
|
|
line := strings.TrimSpace(scanner.Text())
|
|
if line == "" {
|
|
continue
|
|
}
|
|
|
|
matches := syslogRegex.FindStringSubmatch(line)
|
|
if matches == nil {
|
|
continue
|
|
}
|
|
|
|
timestamp, err := time.Parse(time.RFC3339, matches[2])
|
|
if err != nil {
|
|
// Try alternative format
|
|
timestamp, err = time.Parse("2006-01-02T15:04:05.000000-07:00", matches[2])
|
|
if err != nil {
|
|
continue
|
|
}
|
|
}
|
|
|
|
event := models.Event{
|
|
ID: generateEventID(sourcePath, lineNum),
|
|
Timestamp: timestamp,
|
|
Source: matches[4],
|
|
SensorType: "syslog",
|
|
SensorName: matches[3],
|
|
Description: matches[5],
|
|
Severity: severity,
|
|
RawData: line,
|
|
}
|
|
|
|
events = append(events, event)
|
|
}
|
|
|
|
return events
|
|
}
|
|
|
|
func determineSeverityFromPath(path string) models.Severity {
|
|
pathLower := strings.ToLower(path)
|
|
|
|
switch {
|
|
case strings.Contains(pathLower, "emerg") || strings.Contains(pathLower, "alert") ||
|
|
strings.Contains(pathLower, "crit"):
|
|
return models.SeverityCritical
|
|
case strings.Contains(pathLower, "warn") || strings.Contains(pathLower, "error"):
|
|
return models.SeverityWarning
|
|
default:
|
|
return models.SeverityInfo
|
|
}
|
|
}
|
|
|
|
func generateEventID(source string, lineNum int) string {
|
|
parts := strings.Split(source, "/")
|
|
filename := parts[len(parts)-1]
|
|
return strings.TrimSuffix(filename, ".log") + "_" + itoa(lineNum)
|
|
}
|
|
|
|
func itoa(i int) string {
|
|
if i == 0 {
|
|
return "0"
|
|
}
|
|
var b [20]byte
|
|
pos := len(b)
|
|
for i > 0 {
|
|
pos--
|
|
b[pos] = byte('0' + i%10)
|
|
i /= 10
|
|
}
|
|
return string(b[pos:])
|
|
}
|