01dd53241a
Introduced models.LogEntry{Message, CreatedAt} to replace raw strings
in the log pipeline. Timestamps are now formatted at render time, not
baked into stored messages.
- Engine: appendLog stores LogEntry with time.Now()
- Store: LoadLogs returns []LogEntry, selects created_at from DB
- Store: strips legacy [HH:MM] prefix from pre-refactor DB entries
- TUI: sidebar shows "MM/DD HH:MM" from CreatedAt
- TUI: full log view shows "MM/DD HH:MM" from CreatedAt
- SaveLog still receives plain message string (DB handles timestamp)
97 lines
2.3 KiB
Go
97 lines
2.3 KiB
Go
package tui
|
|
|
|
import (
|
|
"fmt"
|
|
"strings"
|
|
|
|
"gitea.lerkolabs.com/lerkolabs/uptop/internal/models"
|
|
)
|
|
|
|
type logSeverity int
|
|
|
|
const (
|
|
severityInfo logSeverity = iota
|
|
severityWarn
|
|
severityDown
|
|
severityUp
|
|
severitySystem
|
|
)
|
|
|
|
func classifyLog(msg string) logSeverity {
|
|
lower := strings.ToLower(msg)
|
|
switch {
|
|
case strings.Contains(lower, "confirmed down"),
|
|
strings.Contains(lower, "is down"),
|
|
strings.Contains(lower, "missed heartbeat"),
|
|
strings.Contains(lower, "alert send failed"):
|
|
return severityDown
|
|
case strings.Contains(lower, "recovered"),
|
|
strings.Contains(lower, "is up"),
|
|
strings.Contains(lower, "recovery"),
|
|
strings.Contains(lower, "first heartbeat"):
|
|
return severityUp
|
|
case strings.Contains(lower, "failed check"),
|
|
strings.Contains(lower, "ssl warning"),
|
|
strings.Contains(lower, "overdue"),
|
|
strings.Contains(lower, "was late"):
|
|
return severityWarn
|
|
case strings.Contains(lower, "engine"),
|
|
strings.Contains(lower, "cluster"),
|
|
strings.Contains(lower, "loaded"),
|
|
strings.Contains(lower, "paused"),
|
|
strings.Contains(lower, "resumed"):
|
|
return severitySystem
|
|
default:
|
|
return severityInfo
|
|
}
|
|
}
|
|
|
|
func isImportantLog(sev logSeverity) bool {
|
|
return sev == severityDown || sev == severityUp || sev == severitySystem
|
|
}
|
|
|
|
func (m Model) renderLogTag(sev logSeverity) string {
|
|
switch sev {
|
|
case severityDown:
|
|
return m.st.dangerStyle.Render(" DOWN ")
|
|
case severityUp:
|
|
return m.st.specialStyle.Render(" UP ")
|
|
case severityWarn:
|
|
return m.st.warnStyle.Render(" WARN ")
|
|
case severitySystem:
|
|
return m.st.titleStyle.Render(" SYS ")
|
|
default:
|
|
return m.st.subtleStyle.Render(" info ")
|
|
}
|
|
}
|
|
|
|
func (m Model) renderLogLine(entry models.LogEntry) string {
|
|
sev := classifyLog(entry.Message)
|
|
tag := m.renderLogTag(sev)
|
|
ts := m.st.subtleStyle.Render(entry.CreatedAt.Local().Format("01/02 15:04"))
|
|
return fmt.Sprintf(" %s %s %s", ts, tag, entry.Message)
|
|
}
|
|
|
|
func (m *Model) refreshLogContent() {
|
|
var rendered []string
|
|
total := 0
|
|
shown := 0
|
|
|
|
for _, entry := range m.engine.GetLogs() {
|
|
if strings.TrimSpace(entry.Message) == "" {
|
|
continue
|
|
}
|
|
total++
|
|
sev := classifyLog(entry.Message)
|
|
if m.logFilterImportant && !isImportantLog(sev) {
|
|
continue
|
|
}
|
|
shown++
|
|
rendered = append(rendered, m.renderLogLine(entry))
|
|
}
|
|
|
|
m.logTotal = total
|
|
m.logShown = shown
|
|
m.logViewport.SetContent(strings.Join(rendered, "\n"))
|
|
}
|