parser: fallback zone-less source timestamps to Europe/Moscow
This commit is contained in:
33
internal/parser/timezone.go
Normal file
33
internal/parser/timezone.go
Normal file
@@ -0,0 +1,33 @@
|
||||
package parser
|
||||
|
||||
import (
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
const fallbackTimezoneName = "Europe/Moscow"
|
||||
|
||||
var (
|
||||
fallbackTimezoneOnce sync.Once
|
||||
fallbackTimezone *time.Location
|
||||
)
|
||||
|
||||
// DefaultArchiveLocation returns the timezone used for source timestamps
|
||||
// that do not contain an explicit offset.
|
||||
func DefaultArchiveLocation() *time.Location {
|
||||
fallbackTimezoneOnce.Do(func() {
|
||||
loc, err := time.LoadLocation(fallbackTimezoneName)
|
||||
if err != nil {
|
||||
fallbackTimezone = time.FixedZone("MSK", 3*60*60)
|
||||
return
|
||||
}
|
||||
fallbackTimezone = loc
|
||||
})
|
||||
return fallbackTimezone
|
||||
}
|
||||
|
||||
// ParseInDefaultArchiveLocation parses timestamps without timezone information
|
||||
// using Europe/Moscow as the assumed source timezone.
|
||||
func ParseInDefaultArchiveLocation(layout, value string) (time.Time, error) {
|
||||
return time.ParseInLocation(layout, value, DefaultArchiveLocation())
|
||||
}
|
||||
3
internal/parser/vendors/inspur/sel.go
vendored
3
internal/parser/vendors/inspur/sel.go
vendored
@@ -6,6 +6,7 @@ import (
|
||||
"time"
|
||||
|
||||
"git.mchus.pro/mchus/logpile/internal/models"
|
||||
"git.mchus.pro/mchus/logpile/internal/parser"
|
||||
)
|
||||
|
||||
// ParseSELList parses selelist.csv file with SEL events
|
||||
@@ -81,7 +82,7 @@ func parseSELTimestamp(dateStr, timeStr string) time.Time {
|
||||
timestampStr := dateStr + " " + timeStr
|
||||
|
||||
// Try parsing with MM/DD/YYYY format
|
||||
t, err := time.Parse("01/02/2006 15:04:05", timestampStr)
|
||||
t, err := parser.ParseInDefaultArchiveLocation("01/02/2006 15:04:05", timestampStr)
|
||||
if err != nil {
|
||||
// Fallback to current time
|
||||
return time.Now()
|
||||
|
||||
@@ -112,7 +112,7 @@ func parseVerboseRunTestStartTimes(content []byte) map[string]time.Time {
|
||||
continue
|
||||
}
|
||||
|
||||
ts, err := time.ParseInLocation("2006-01-02 15:04:05", strings.TrimSpace(matches[1]), time.UTC)
|
||||
ts, err := parser.ParseInDefaultArchiveLocation("2006-01-02 15:04:05", strings.TrimSpace(matches[1]))
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
@@ -135,7 +135,7 @@ func parseRunLogTestStartTimes(content []byte) map[string]time.Time {
|
||||
if len(matches) != 2 {
|
||||
continue
|
||||
}
|
||||
parsed, err := time.ParseInLocation("Mon, 02 Jan 2006 15:04:05", strings.TrimSpace(matches[1]), time.UTC)
|
||||
parsed, err := parser.ParseInDefaultArchiveLocation("Mon, 02 Jan 2006 15:04:05", strings.TrimSpace(matches[1]))
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
@@ -178,7 +178,7 @@ func parseModsStartTime(content []byte) time.Time {
|
||||
if tsRaw == "" {
|
||||
return time.Time{}
|
||||
}
|
||||
ts, err := time.ParseInLocation("Mon Jan 2 15:04:05 2006", tsRaw, time.UTC)
|
||||
ts, err := parser.ParseInDefaultArchiveLocation("Mon Jan 2 15:04:05 2006", tsRaw)
|
||||
if err != nil {
|
||||
return time.Time{}
|
||||
}
|
||||
|
||||
@@ -23,10 +23,10 @@ func TestParseVerboseRunTestStartTimes(t *testing.T) {
|
||||
if gpu.IsZero() {
|
||||
t.Fatalf("expected gpu_fieldiag timestamp")
|
||||
}
|
||||
if nvs.Format(time.RFC3339) != "2026-01-22T09:11:32Z" {
|
||||
if nvs.UTC().Format(time.RFC3339) != "2026-01-22T06:11:32Z" {
|
||||
t.Fatalf("unexpected nvswitch timestamp: %s", nvs.Format(time.RFC3339))
|
||||
}
|
||||
if gpu.Format(time.RFC3339) != "2026-01-22T09:45:36Z" {
|
||||
if gpu.UTC().Format(time.RFC3339) != "2026-01-22T06:45:36Z" {
|
||||
t.Fatalf("unexpected gpu_fieldiag timestamp: %s", gpu.Format(time.RFC3339))
|
||||
}
|
||||
}
|
||||
@@ -40,13 +40,13 @@ Testing nvswitch OK [ 9:25s ]
|
||||
`)
|
||||
|
||||
got := parseRunLogTestStartTimes(content)
|
||||
if got["gpumem"].Format(time.RFC3339) != "2026-01-22T07:42:26Z" {
|
||||
if got["gpumem"].UTC().Format(time.RFC3339) != "2026-01-22T04:42:26Z" {
|
||||
t.Fatalf("unexpected gpumem start: %s", got["gpumem"].Format(time.RFC3339))
|
||||
}
|
||||
if got["gpustress"].Format(time.RFC3339) != "2026-01-22T08:08:38Z" {
|
||||
if got["gpustress"].UTC().Format(time.RFC3339) != "2026-01-22T05:08:38Z" {
|
||||
t.Fatalf("unexpected gpustress start: %s", got["gpustress"].Format(time.RFC3339))
|
||||
}
|
||||
if got["nvswitch"].Format(time.RFC3339) != "2026-01-22T08:15:48Z" {
|
||||
if got["nvswitch"].UTC().Format(time.RFC3339) != "2026-01-22T05:15:48Z" {
|
||||
t.Fatalf("unexpected nvswitch start: %s", got["nvswitch"].Format(time.RFC3339))
|
||||
}
|
||||
}
|
||||
@@ -101,10 +101,10 @@ func TestCollectGPUAndNVSwitchCheckTimes_FromVerboseRun(t *testing.T) {
|
||||
}
|
||||
|
||||
got := CollectGPUAndNVSwitchCheckTimes(files)
|
||||
if got.GPUDefault.Format(time.RFC3339) != "2026-01-22T09:45:36Z" {
|
||||
if got.GPUDefault.UTC().Format(time.RFC3339) != "2026-01-22T06:45:36Z" {
|
||||
t.Fatalf("unexpected GPU check time: %s", got.GPUDefault.Format(time.RFC3339))
|
||||
}
|
||||
if got.NVSwitchDefault.Format(time.RFC3339) != "2026-01-22T09:11:32Z" {
|
||||
if got.NVSwitchDefault.UTC().Format(time.RFC3339) != "2026-01-22T06:11:32Z" {
|
||||
t.Fatalf("unexpected NVSwitch check time: %s", got.NVSwitchDefault.Format(time.RFC3339))
|
||||
}
|
||||
}
|
||||
@@ -128,16 +128,16 @@ MODS start: Thu Jan 22 09:11:32 2026
|
||||
}
|
||||
|
||||
got := CollectGPUAndNVSwitchCheckTimes(files)
|
||||
if got.GPUBySerial["1653925025497"].Format(time.RFC3339) != "2026-01-22T09:45:36Z" {
|
||||
if got.GPUBySerial["1653925025497"].UTC().Format(time.RFC3339) != "2026-01-22T06:45:36Z" {
|
||||
t.Fatalf("unexpected GPU serial check time: %s", got.GPUBySerial["1653925025497"].Format(time.RFC3339))
|
||||
}
|
||||
if got.GPUBySlot["GPUSXM5"].Format(time.RFC3339) != "2026-01-22T09:45:36Z" {
|
||||
if got.GPUBySlot["GPUSXM5"].UTC().Format(time.RFC3339) != "2026-01-22T06:45:36Z" {
|
||||
t.Fatalf("unexpected GPU slot check time: %s", got.GPUBySlot["GPUSXM5"].Format(time.RFC3339))
|
||||
}
|
||||
if got.NVSwitchBySlot["NVSWITCH0"].Format(time.RFC3339) != "2026-01-22T09:11:32Z" {
|
||||
if got.NVSwitchBySlot["NVSWITCH0"].UTC().Format(time.RFC3339) != "2026-01-22T06:11:32Z" {
|
||||
t.Fatalf("unexpected NVSwitch0 check time: %s", got.NVSwitchBySlot["NVSWITCH0"].Format(time.RFC3339))
|
||||
}
|
||||
if got.NVSwitchBySlot["NVSWITCH3"].Format(time.RFC3339) != "2026-01-22T09:11:32Z" {
|
||||
if got.NVSwitchBySlot["NVSWITCH3"].UTC().Format(time.RFC3339) != "2026-01-22T06:11:32Z" {
|
||||
t.Fatalf("unexpected NVSwitch3 check time: %s", got.NVSwitchBySlot["NVSWITCH3"].Format(time.RFC3339))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -235,8 +235,8 @@ func TestNVIDIAParser_ComponentCheckTimes_RealArchive07900(t *testing.T) {
|
||||
t.Fatalf("expected hardware in parsed result")
|
||||
}
|
||||
|
||||
expectedGPU := time.Date(2026, 1, 22, 9, 45, 36, 0, time.UTC)
|
||||
expectedNVSwitch := time.Date(2026, 1, 22, 9, 11, 32, 0, time.UTC)
|
||||
expectedGPU := time.Date(2026, 1, 22, 6, 45, 36, 0, time.UTC)
|
||||
expectedNVSwitch := time.Date(2026, 1, 22, 6, 11, 32, 0, time.UTC)
|
||||
|
||||
if len(result.Hardware.GPUs) == 0 {
|
||||
t.Fatalf("expected GPUs in parsed result")
|
||||
|
||||
2
internal/parser/vendors/unraid/parser.go
vendored
2
internal/parser/vendors/unraid/parser.go
vendored
@@ -559,7 +559,7 @@ func parseSyslogLine(line string) (time.Time, string, models.Severity) {
|
||||
|
||||
// Parse timestamp (add current year)
|
||||
year := time.Now().Year()
|
||||
if ts, err := time.Parse("Jan 2 15:04:05 2006", timeStr+" "+strconv.Itoa(year)); err == nil {
|
||||
if ts, err := parser.ParseInDefaultArchiveLocation("Jan 2 15:04:05 2006", timeStr+" "+strconv.Itoa(year)); err == nil {
|
||||
timestamp = ts
|
||||
}
|
||||
}
|
||||
|
||||
2
internal/parser/vendors/xigmanas/parser.go
vendored
2
internal/parser/vendors/xigmanas/parser.go
vendored
@@ -431,7 +431,7 @@ func parseEventTimestamp(line string) time.Time {
|
||||
prefixRe := regexp.MustCompile(`^[A-Z][a-z]{2}\s+\d{1,2}\s+\d{2}:\d{2}:\d{2}`)
|
||||
if prefix := prefixRe.FindString(line); prefix != "" {
|
||||
year := time.Now().Year()
|
||||
if ts, err := time.Parse("Jan 2 15:04:05 2006", prefix+" "+strconv.Itoa(year)); err == nil {
|
||||
if ts, err := parser.ParseInDefaultArchiveLocation("Jan 2 15:04:05 2006", prefix+" "+strconv.Itoa(year)); err == nil {
|
||||
return ts
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user