Files
logpile/internal/parser/vendors/inspur/syslog.go
Michael Chus 512957545a 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>
2026-01-25 04:11:23 +03:00

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:])
}