feat(inspur): source-PRI timezone timeline, PPIN serial, NVMe fault storage status
Event ingestion now uses the source syslog PRI and an explicit-offset timezone timeline instead of assuming host-local time. CPU PPIN is exported as the source-backed CPU serial, and an active NVMe fault SEL event promotes the matching drive's storage status. See ADL-056, ADL-057. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
07c270cda2
commit
e7b8a8badc
+50
-6
@@ -3,6 +3,7 @@ package inspur
|
||||
import (
|
||||
"bufio"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
@@ -11,16 +12,14 @@ import (
|
||||
|
||||
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*(.*)$`)
|
||||
syslogRegex = regexp.MustCompile(`^<(\d+)>\s*(\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}[^\s]*)\s+(\S+)\s+(\S+):\s*(.*)$`)
|
||||
bootRelativeMessageRegex = regexp.MustCompile(`^\[\s*\d+(?:\.\d+)?\]`)
|
||||
)
|
||||
|
||||
// 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
|
||||
|
||||
@@ -35,6 +34,10 @@ func ParseSyslog(content []byte, sourcePath string) []models.Event {
|
||||
if matches == nil {
|
||||
continue
|
||||
}
|
||||
priority, err := strconv.Atoi(matches[1])
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
timestamp, err := time.Parse(time.RFC3339, matches[2])
|
||||
if err != nil {
|
||||
@@ -44,6 +47,14 @@ func ParseSyslog(content []byte, sourcePath string) []models.Event {
|
||||
continue
|
||||
}
|
||||
}
|
||||
message := strings.TrimSpace(matches[5])
|
||||
// Some AMI BMC boots emit a fabricated 1970 wall-clock timestamp while
|
||||
// the payload only carries seconds since boot. Without a trustworthy
|
||||
// boot epoch this cannot become a wall-clock event, so omit it instead
|
||||
// of exporting either 1970 or the archive collection time.
|
||||
if timestamp.Year() <= 1971 && bootRelativeMessageRegex.MatchString(message) {
|
||||
continue
|
||||
}
|
||||
|
||||
event := models.Event{
|
||||
ID: generateEventID(sourcePath, lineNum),
|
||||
@@ -51,8 +62,8 @@ func ParseSyslog(content []byte, sourcePath string) []models.Event {
|
||||
Source: "syslog",
|
||||
SensorType: "syslog",
|
||||
SensorName: matches[4],
|
||||
Description: matches[5],
|
||||
Severity: severity,
|
||||
Description: message,
|
||||
Severity: determineSyslogSeverity(priority, message, sourcePath),
|
||||
RawData: line,
|
||||
}
|
||||
|
||||
@@ -62,6 +73,39 @@ func ParseSyslog(content []byte, sourcePath string) []models.Event {
|
||||
return events
|
||||
}
|
||||
|
||||
func determineSyslogSeverity(priority int, message, sourcePath string) models.Severity {
|
||||
// These AMI driver start-up/status strings are routed to alert.log and
|
||||
// warning.log despite not describing a fault. The PRI value is therefore
|
||||
// not trustworthy for this small, observed set of benign messages.
|
||||
lowerMessage := strings.ToLower(message)
|
||||
benignMessages := []string{
|
||||
"helper module driver version",
|
||||
"copyright (c)",
|
||||
"color depth is 15 bpp or higher",
|
||||
"new driver 0 directmode 1",
|
||||
}
|
||||
for _, benign := range benignMessages {
|
||||
if strings.Contains(lowerMessage, benign) {
|
||||
return models.SeverityInfo
|
||||
}
|
||||
}
|
||||
|
||||
// RFC 5424 severity is stored in the low three bits of PRI:
|
||||
// 0..2 emergency/alert/critical, 3..4 error/warning, 5..7 notice/info/debug.
|
||||
if priority >= 0 {
|
||||
switch priority & 7 {
|
||||
case 0, 1, 2:
|
||||
return models.SeverityCritical
|
||||
case 3, 4:
|
||||
return models.SeverityWarning
|
||||
default:
|
||||
return models.SeverityInfo
|
||||
}
|
||||
}
|
||||
|
||||
return determineSeverityFromPath(sourcePath)
|
||||
}
|
||||
|
||||
func determineSeverityFromPath(path string) models.Severity {
|
||||
pathLower := strings.ToLower(path)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user