Show 90-day uptime bars on the status page
Every check is also counted in a per-day table that outlives the raw checks, so the public page can draw one bar per UTC day with a tooltip, as most hosted status pages do. Existing databases are backfilled once from the checks they still have. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
73f45fb3ae
commit
4ea4fe5289
7 files changed
+221
-14
No files matched your search
@@ -45,6 +45,9 @@ CREATE INDEX IF NOT EXISTS messages_topic ON messages(topic, time);
|
||||
CREATE TABLE IF NOT EXISTS checks (
|
||||
monitor_id TEXT NOT NULL, time INTEGER NOT NULL, ok INTEGER NOT NULL, ms INTEGER NOT NULL, detail TEXT NOT NULL);
|
||||
CREATE INDEX IF NOT EXISTS checks_monitor ON checks(monitor_id, time);
|
||||
-- One row per monitor per UTC day, kept far longer than raw checks: it feeds the status page's uptime bars.
|
||||
CREATE TABLE IF NOT EXISTS daily (
|
||||
monitor_id TEXT NOT NULL, day TEXT NOT NULL, checks INTEGER NOT NULL, fails INTEGER NOT NULL, PRIMARY KEY (monitor_id, day));
|
||||
CREATE TABLE IF NOT EXISTS mstate (
|
||||
monitor_id TEXT PRIMARY KEY, status TEXT NOT NULL, since INTEGER NOT NULL, last_check INTEGER NOT NULL,
|
||||
last_ms INTEGER NOT NULL, fails INTEGER NOT NULL, last_ping INTEGER NOT NULL, detail TEXT NOT NULL);
|
||||
@@ -78,7 +81,19 @@ func OpenStore(dir string, box *secretbox.Box) (*Store, error) {
|
||||
db.Close()
|
||||
return nil, err
|
||||
}
|
||||
return &Store{db: db, box: box}, nil
|
||||
st := &Store{db: db, box: box}
|
||||
st.backfillDaily()
|
||||
return st, nil
|
||||
}
|
||||
|
||||
// backfillDaily fills the daily table from the raw checks, but only when it is empty: a database
|
||||
// from before the table existed. After that every check is counted as it is recorded.
|
||||
func (s *Store) backfillDaily() {
|
||||
var have int
|
||||
if s.db.QueryRow(`SELECT count(*) FROM daily`).Scan(&have) == nil && have == 0 {
|
||||
s.db.Exec(`INSERT OR IGNORE INTO daily(monitor_id,day,checks,fails)
|
||||
SELECT monitor_id, date(time,'unixepoch'), count(*), count(*)-sum(ok) FROM checks GROUP BY monitor_id, date(time,'unixepoch')`)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Store) Close() error { return s.db.Close() }
|
||||
@@ -234,6 +249,7 @@ func (s *Store) events(scope, ref string) []Event {
|
||||
func (s *Store) prune(now time.Time, messageDays, checkDays int) {
|
||||
s.db.Exec(`DELETE FROM messages WHERE time < ?`, now.AddDate(0, 0, -messageDays).Unix())
|
||||
s.db.Exec(`DELETE FROM checks WHERE time < ?`, now.AddDate(0, 0, -checkDays).Unix())
|
||||
s.db.Exec(`DELETE FROM daily WHERE day < ?`, now.UTC().AddDate(0, 0, -400).Format("2006-01-02"))
|
||||
s.db.Exec(`DELETE FROM sessions WHERE expires < ?`, now.Unix())
|
||||
s.db.Exec(`DELETE FROM alerts WHERE status='resolved' AND resolved_at < ? AND incident_id=''`, now.AddDate(0, 0, -90).Unix())
|
||||
}
|
||||
Reference in new issue
Block a user