Improve Redfish recovery flow and raw export timing diagnostics

This commit is contained in:
2026-02-28 16:55:58 +03:00
parent 9a30705c9a
commit e0146adfff
10 changed files with 1437 additions and 58 deletions

View File

@@ -197,6 +197,11 @@ func buildHumanReadableCollectionLog(pkg *RawExportPackage, result *models.Analy
if pkg.Source.Filename != "" {
fmt.Fprintf(&b, "Source Filename: %s\n", pkg.Source.Filename)
}
if startedAt, finishedAt, ok := collectLogTimeBounds(pkg.Source.CollectLogs); ok {
fmt.Fprintf(&b, "Collection Started: %s\n", startedAt.Format(time.RFC3339Nano))
fmt.Fprintf(&b, "Collection Finished: %s\n", finishedAt.Format(time.RFC3339Nano))
fmt.Fprintf(&b, "Collection Duration: %s\n", formatRawExportDuration(finishedAt.Sub(startedAt)))
}
}
if pkg != nil && len(pkg.Source.CollectLogs) > 0 {
@@ -279,6 +284,42 @@ func buildHumanReadableCollectionLog(pkg *RawExportPackage, result *models.Analy
return b.String()
}
func collectLogTimeBounds(lines []string) (time.Time, time.Time, bool) {
var first time.Time
var last time.Time
for _, line := range lines {
line = strings.TrimSpace(line)
if line == "" {
continue
}
tsToken := line
if idx := strings.IndexByte(line, ' '); idx > 0 {
tsToken = line[:idx]
}
ts, err := time.Parse(time.RFC3339Nano, tsToken)
if err != nil {
continue
}
if first.IsZero() || ts.Before(first) {
first = ts
}
if last.IsZero() || ts.After(last) {
last = ts
}
}
if first.IsZero() || last.IsZero() || last.Before(first) {
return time.Time{}, time.Time{}, false
}
return first, last, true
}
func formatRawExportDuration(d time.Duration) string {
if d < 0 {
d = 0
}
return d.Round(time.Second).String()
}
func buildParserFieldSummary(result *models.AnalysisResult) map[string]any {
out := map[string]any{
"generated_at": time.Now().UTC(),

View File

@@ -0,0 +1,46 @@
package server
import (
"strings"
"testing"
)
func TestCollectLogTimeBounds(t *testing.T) {
lines := []string{
"2026-02-28T13:10:13.7442032Z Задача поставлена в очередь",
"not-a-timestamp line",
"2026-02-28T13:31:00.5077486Z Сбор завершен",
}
startedAt, finishedAt, ok := collectLogTimeBounds(lines)
if !ok {
t.Fatalf("expected bounds to be parsed")
}
if got := formatRawExportDuration(finishedAt.Sub(startedAt)); got != "20m47s" {
t.Fatalf("unexpected duration: %s", got)
}
}
func TestBuildHumanReadableCollectionLog_IncludesDurationHeader(t *testing.T) {
pkg := &RawExportPackage{
Format: rawExportFormatV1,
Source: RawExportSource{
Kind: "live_redfish",
CollectLogs: []string{
"2026-02-28T13:10:13.7442032Z Redfish: подключение к BMC...",
"2026-02-28T13:31:00.5077486Z Сбор завершен",
},
},
}
logText := buildHumanReadableCollectionLog(pkg, nil, "LOGPile test")
for _, token := range []string{
"Collection Started:",
"Collection Finished:",
"Collection Duration:",
} {
if !strings.Contains(logText, token) {
t.Fatalf("expected %q in log header", token)
}
}
}