refactor: separate log timestamp from message as structured LogEntry
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)
This commit is contained in:
+13
-11
@@ -40,7 +40,7 @@ type Engine struct {
|
||||
liveState map[int]models.Site
|
||||
|
||||
logMu sync.RWMutex
|
||||
logStore []string
|
||||
logStore []models.LogEntry
|
||||
|
||||
activeMu sync.RWMutex
|
||||
isActive bool
|
||||
@@ -152,11 +152,13 @@ func fmtDurationShort(d time.Duration) string {
|
||||
// appendLog adds a timestamped entry to the in-memory ring buffer and returns
|
||||
// it. It never touches the database, so it is safe to call from the db-write
|
||||
// drop/error path without recursing back through the write queue.
|
||||
func (e *Engine) appendLog(msg string) string {
|
||||
ts := time.Now().Format("15:04:05")
|
||||
entry := fmt.Sprintf("[%s] %s", ts, sanitizeLog(msg))
|
||||
func (e *Engine) appendLog(msg string) models.LogEntry {
|
||||
entry := models.LogEntry{
|
||||
Message: sanitizeLog(msg),
|
||||
CreatedAt: time.Now(),
|
||||
}
|
||||
e.logMu.Lock()
|
||||
e.logStore = append([]string{entry}, e.logStore...)
|
||||
e.logStore = append([]models.LogEntry{entry}, e.logStore...)
|
||||
if len(e.logStore) > maxLogEntries {
|
||||
e.logStore = e.logStore[:maxLogEntries]
|
||||
}
|
||||
@@ -166,7 +168,7 @@ func (e *Engine) appendLog(msg string) string {
|
||||
|
||||
func (e *Engine) AddLog(msg string) {
|
||||
entry := e.appendLog(msg)
|
||||
e.enqueueWrite(writeLog{message: entry})
|
||||
e.enqueueWrite(writeLog{message: entry.Message})
|
||||
}
|
||||
|
||||
// enqueueWrite hands a persistence task to the writer goroutine without
|
||||
@@ -246,16 +248,16 @@ func (e *Engine) Stop() {
|
||||
}
|
||||
|
||||
func (e *Engine) InitLogs() {
|
||||
logs, err := e.db.LoadLogs(context.Background(), maxLogEntries)
|
||||
entries, err := e.db.LoadLogs(context.Background(), maxLogEntries)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if len(logs) == 0 {
|
||||
if len(entries) == 0 {
|
||||
return
|
||||
}
|
||||
e.logMu.Lock()
|
||||
defer e.logMu.Unlock()
|
||||
e.logStore = logs
|
||||
e.logStore = entries
|
||||
}
|
||||
|
||||
// InitAlertHealth restores persisted alert send health so the dashboard shows real
|
||||
@@ -278,10 +280,10 @@ func (e *Engine) InitAlertHealth() {
|
||||
}
|
||||
}
|
||||
|
||||
func (e *Engine) GetLogs() []string {
|
||||
func (e *Engine) GetLogs() []models.LogEntry {
|
||||
e.logMu.RLock()
|
||||
defer e.logMu.RUnlock()
|
||||
logs := make([]string, len(e.logStore))
|
||||
logs := make([]models.LogEntry, len(e.logStore))
|
||||
copy(logs, e.logStore)
|
||||
return logs
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@ type mockStore struct {
|
||||
sites []models.SiteConfig
|
||||
alerts map[int]models.AlertConfig
|
||||
maintenance map[int]bool
|
||||
logs []string
|
||||
logs []models.LogEntry
|
||||
history map[int][]models.CheckRecord
|
||||
savedChecks []savedCheck
|
||||
savedLogs []string
|
||||
@@ -103,7 +103,7 @@ func (m *mockStore) SaveLog(_ context.Context, msg string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *mockStore) LoadLogs(_ context.Context, _ int) ([]string, error) {
|
||||
func (m *mockStore) LoadLogs(_ context.Context, _ int) ([]models.LogEntry, error) {
|
||||
return m.logs, nil
|
||||
}
|
||||
|
||||
@@ -330,7 +330,7 @@ func TestHandleStatusChange_AlertSuppressedMaintenance(t *testing.T) {
|
||||
logs := e.GetLogs()
|
||||
found := false
|
||||
for _, l := range logs {
|
||||
if containsStr(l, "suppressed") {
|
||||
if containsStr(l.Message, "suppressed") {
|
||||
found = true
|
||||
break
|
||||
}
|
||||
@@ -973,14 +973,17 @@ func TestAddLog_PrependAndCap(t *testing.T) {
|
||||
if len(logs) != 100 {
|
||||
t.Errorf("expected 100 logs, got %d", len(logs))
|
||||
}
|
||||
if !containsStr(logs[0], "log-104") {
|
||||
t.Errorf("expected newest log first, got %s", logs[0])
|
||||
if !containsStr(logs[0].Message, "log-104") {
|
||||
t.Errorf("expected newest log first, got %s", logs[0].Message)
|
||||
}
|
||||
}
|
||||
|
||||
func TestInitLogs_LoadsFromDB(t *testing.T) {
|
||||
ms := newMockStore()
|
||||
ms.logs = []string{"old-log-1", "old-log-2"}
|
||||
ms.logs = []models.LogEntry{
|
||||
{Message: "old-log-1"},
|
||||
{Message: "old-log-2"},
|
||||
}
|
||||
e := newTestEngine(ms)
|
||||
e.InitLogs()
|
||||
|
||||
|
||||
Reference in New Issue
Block a user