release: 2026.05.1 — distributed probing, config-as-code, TUI polish #15

Merged
lerko merged 47 commits from develop into main 2026-05-16 20:03:54 +00:00
7 changed files with 59 additions and 0 deletions
Showing only changes of commit ed082e4080 - Show all commits
+1
View File
@@ -260,6 +260,7 @@ func runServe(args []string) {
defer cancel() defer cancel()
eng.InitHistory() eng.InitHistory()
eng.InitLogs()
eng.Start(ctx) eng.Start(ctx)
server.Start(server.ServerConfig{ server.Start(server.ServerConfig{
+2
View File
@@ -50,6 +50,8 @@ func (m *mockStore) GetNode(string) (models.ProbeNode, error) { return m
func (m *mockStore) GetAllNodes() ([]models.ProbeNode, error) { return nil, nil } func (m *mockStore) GetAllNodes() ([]models.ProbeNode, error) { return nil, nil }
func (m *mockStore) UpdateNodeLastSeen(string) error { return nil } func (m *mockStore) UpdateNodeLastSeen(string) error { return nil }
func (m *mockStore) DeleteNode(string) error { return nil } func (m *mockStore) DeleteNode(string) error { return nil }
func (m *mockStore) SaveLog(string) error { return nil }
func (m *mockStore) LoadLogs(int) ([]string, error) { return nil, nil }
func TestMetricsHandler(t *testing.T) { func TestMetricsHandler(t *testing.T) {
ms := &mockStore{ ms := &mockStore{
+14
View File
@@ -68,6 +68,20 @@ func (e *Engine) AddLog(msg string) {
if len(e.logStore) > 100 { if len(e.logStore) > 100 {
e.logStore = e.logStore[:100] e.logStore = e.logStore[:100]
} }
go func() { _ = e.db.SaveLog(entry) }()
}
func (e *Engine) InitLogs() {
logs, err := e.db.LoadLogs(100)
if err != nil {
return
}
if len(logs) == 0 {
return
}
e.logMu.Lock()
defer e.logMu.Unlock()
e.logStore = logs
} }
func (e *Engine) GetLogs() []string { func (e *Engine) GetLogs() []string {
+5
View File
@@ -51,6 +51,11 @@ func (d *PostgresDialect) CreateTablesSQL() []string {
last_seen TIMESTAMP DEFAULT NOW(), last_seen TIMESTAMP DEFAULT NOW(),
version TEXT DEFAULT '' version TEXT DEFAULT ''
)`, )`,
`CREATE TABLE IF NOT EXISTS logs (
id SERIAL PRIMARY KEY,
message TEXT NOT NULL,
created_at TIMESTAMP DEFAULT NOW()
)`,
} }
} }
+5
View File
@@ -51,6 +51,11 @@ func (d *SQLiteDialect) CreateTablesSQL() []string {
last_seen DATETIME DEFAULT CURRENT_TIMESTAMP, last_seen DATETIME DEFAULT CURRENT_TIMESTAMP,
version TEXT DEFAULT '' version TEXT DEFAULT ''
)`, )`,
`CREATE TABLE IF NOT EXISTS logs (
id INTEGER PRIMARY KEY AUTOINCREMENT,
message TEXT NOT NULL,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
)`,
} }
} }
+28
View File
@@ -300,6 +300,34 @@ func (s *SQLStore) DeleteNode(id string) error {
return err return err
} }
func (s *SQLStore) SaveLog(message string) error {
_, err := s.db.Exec(s.q("INSERT INTO logs (message) VALUES (?)"), message)
if err != nil {
return err
}
_, err = s.db.Exec(s.q(`DELETE FROM logs WHERE id NOT IN (
SELECT id FROM logs ORDER BY created_at DESC LIMIT 200
)`))
return err
}
func (s *SQLStore) LoadLogs(limit int) ([]string, error) {
rows, err := s.db.Query(s.q("SELECT message FROM logs ORDER BY created_at DESC LIMIT ?"), limit)
if err != nil {
return nil, err
}
defer rows.Close()
var logs []string
for rows.Next() {
var msg string
if err := rows.Scan(&msg); err != nil {
return logs, err
}
logs = append(logs, msg)
}
return logs, rows.Err()
}
func (s *SQLStore) LoadAllHistory(limit int) (map[int][]models.CheckRecord, error) { func (s *SQLStore) LoadAllHistory(limit int) (map[int][]models.CheckRecord, error) {
result := make(map[int][]models.CheckRecord) result := make(map[int][]models.CheckRecord)
rows, err := s.db.Query(s.q(` rows, err := s.db.Query(s.q(`
+4
View File
@@ -45,6 +45,10 @@ type Store interface {
UpdateNodeLastSeen(id string) error UpdateNodeLastSeen(id string) error
DeleteNode(id string) error DeleteNode(id string) error
// Logs
SaveLog(message string) error
LoadLogs(limit int) ([]string, error)
// Backup & Restore // Backup & Restore
ExportData() (models.Backup, error) ExportData() (models.Backup, error)
ImportData(data models.Backup) error ImportData(data models.Backup) error