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
+72
-1
@@ -1,6 +1,12 @@
|
||||
package inspur
|
||||
|
||||
import "testing"
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"git.mchus.pro/mchus/logpile/internal/models"
|
||||
baseparser "git.mchus.pro/mchus/logpile/internal/parser"
|
||||
)
|
||||
|
||||
func TestParseIDLLog_UsesBMCSourceForEventLogs(t *testing.T) {
|
||||
content := []byte(`|2025-12-02T17:54:27+08:00|MEMORY|Assert|Warning|0C180401|CPU1_C4D0 Memory Device Disabled - Assert|`)
|
||||
@@ -17,6 +23,14 @@ func TestParseIDLLog_UsesBMCSourceForEventLogs(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseIDLLog_DeassertedFaultIsInfo(t *testing.T) {
|
||||
content := []byte(`|2026-05-07T23:57:08+08:00|BMC|Deassert|Critical|1800B002|Sys_Health Transition to Critical from less severe - Deassert|`)
|
||||
events := ParseIDLLog(content)
|
||||
if len(events) != 1 || events[0].Severity != models.SeverityInfo {
|
||||
t.Fatalf("expected deasserted IDL fault to be informational, got %+v", events)
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseSyslog_UsesHostSourceAndProcessAsSensorName(t *testing.T) {
|
||||
content := []byte(`<13>2026-03-15T14:03:11+00:00 host123 systemd[1]: Started Example Service`)
|
||||
|
||||
@@ -31,3 +45,60 @@ func TestParseSyslog_UsesHostSourceAndProcessAsSensorName(t *testing.T) {
|
||||
t.Fatalf("expected process name in sensor/component slot, got %#v", events[0])
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseSyslog_UsesPriorityAndDowngradesKnownBenignMessages(t *testing.T) {
|
||||
content := []byte("<1> 1970-01-01T08:01:38.795020+08:00 host kernel: [ 17.763621] Helper Module Driver Version 1.2\n" +
|
||||
"<1> 2026-01-29T16:24:12.888636+08:00 host kernel: [ 16.191801] Helper Module Driver Version 1.2\n" +
|
||||
"<132> 2026-07-25T08:42:47.001654+03:00 host kernel: [100009.801150] Color Depth is 15 bpp or higher\n" +
|
||||
"<130> 2026-07-25T08:43:48.001964+03:00 host MCTPMain: MCTP_ERROR: No Response for Application. Timing-out...TimeoutMsec:4000\n")
|
||||
|
||||
events := ParseSyslog(content, "onekeylog/log/syslog/alert.log")
|
||||
if len(events) != 3 {
|
||||
t.Fatalf("expected 3 events, got %d", len(events))
|
||||
}
|
||||
if events[0].Severity != models.SeverityInfo {
|
||||
t.Fatalf("expected benign driver alert to be info, got %#v", events[0])
|
||||
}
|
||||
if events[1].Severity != models.SeverityInfo {
|
||||
t.Fatalf("expected KVM status line to be info, got %#v", events[1])
|
||||
}
|
||||
if events[2].Severity != models.SeverityCritical {
|
||||
t.Fatalf("expected PRI=2 MCTP fault to be critical, got %#v", events[2])
|
||||
}
|
||||
}
|
||||
|
||||
func TestParserIncludesCriticalSyslogMCTPAndMESelfTest(t *testing.T) {
|
||||
files := []baseparser.ExtractedFile{{
|
||||
Path: "onekeylog/log/syslog/crit.log",
|
||||
Content: []byte("<130> 2026-07-25T08:42:47.001654+03:00 host MCTPMain: MCTP_ERROR: No Response for Application. Timing-out...TimeoutMsec:4000\n" +
|
||||
"<130> 2026-07-25T08:43:28.072198+03:00 host IPMIMain: Me self-tests is not normal, return code is 195!\n"),
|
||||
}}
|
||||
|
||||
result, err := (&Parser{}).Parse(files)
|
||||
if err != nil {
|
||||
t.Fatalf("parse: %v", err)
|
||||
}
|
||||
if len(result.Events) != 2 {
|
||||
t.Fatalf("expected both critical syslog events, got %d: %+v", len(result.Events), result.Events)
|
||||
}
|
||||
for _, event := range result.Events {
|
||||
if event.Severity != models.SeverityCritical {
|
||||
t.Fatalf("expected critical event, got %#v", event)
|
||||
}
|
||||
}
|
||||
if result.Events[0].Timestamp.After(result.Events[1].Timestamp) {
|
||||
t.Fatalf("events are not sorted: %+v", result.Events)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSortInspurEventsPlacesUnknownTimestampsLast(t *testing.T) {
|
||||
events := []models.Event{
|
||||
{ID: "late", Timestamp: time.Date(2026, 7, 25, 8, 0, 0, 0, time.UTC)},
|
||||
{ID: "unknown"},
|
||||
{ID: "early", Timestamp: time.Date(2026, 7, 24, 8, 0, 0, 0, time.UTC)},
|
||||
}
|
||||
sortInspurEvents(events)
|
||||
if events[0].ID != "early" || events[1].ID != "late" || events[2].ID != "unknown" {
|
||||
t.Fatalf("unexpected event order: %+v", events)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user