Files
knox/internal/db/metrics.go
T
david d6d2a24ddc style: gofmt all packages (#4)
Applies gofmt to the 18 files that were already unformatted at HEAD (pre-existing debt — 122 insertions / 122 deletions, whitespace plus import-block reorderings only; `git diff -w` confirms no semantic changes).

Kept on its own branch so the functional change set (see the review-hardening PR) stays reviewable without formatting noise.

Verified: go build, go vet, go test ./... pass on this branch; a merge simulation with the functional branch produces a clean 3-way merge with all tests green.
Reviewed-on: #4
Co-authored-by: David Gwilliam <dhgwilliam@gmail.com>
Co-committed-by: David Gwilliam <dhgwilliam@gmail.com>
2026-09-17 09:05:57 +00:00

109 lines
3.1 KiB
Go

package db
// MetricsSnapshot holds the scrape-time gauges derived from the database.
type MetricsSnapshot struct {
Observations int
ObservationsLast24h int
BySource map[string]int
Entries int
Projects int
Sessions int
PendingReflections int
ThreadsByStatus map[string]int
Peers int
ByOriginNode map[string]int // node_id → observation count
KnowledgeVector map[string]int64 // node_id → max hcl
EarliestObservation string
}
// MetricsSnapshot computes database-derived gauges for Prometheus scraping.
// All queries are cheap aggregations; nothing is stored or mutated.
func (k *KnoxDB) MetricsSnapshot() (*MetricsSnapshot, error) {
s := &MetricsSnapshot{
BySource: make(map[string]int),
ThreadsByStatus: make(map[string]int),
ByOriginNode: make(map[string]int),
}
if err := k.db.QueryRow("SELECT COUNT(*) FROM observations").Scan(&s.Observations); err != nil {
return nil, err
}
if err := k.db.QueryRow("SELECT COUNT(*) FROM observations WHERE collected_at > datetime('now', '-1 day')").Scan(&s.ObservationsLast24h); err != nil {
return nil, err
}
if err := k.db.QueryRow("SELECT COUNT(*) FROM entries").Scan(&s.Entries); err != nil {
return nil, err
}
if err := k.db.QueryRow("SELECT COUNT(DISTINCT project) FROM entries").Scan(&s.Projects); err != nil {
return nil, err
}
if err := k.db.QueryRow("SELECT COUNT(*) FROM sessions").Scan(&s.Sessions); err != nil {
return nil, err
}
if err := k.db.QueryRow("SELECT COUNT(*) FROM sessions WHERE indexed=0").Scan(&s.PendingReflections); err != nil {
return nil, err
}
if err := k.db.QueryRow("SELECT COUNT(*) FROM peers").Scan(&s.Peers); err != nil {
return nil, err
}
if err := k.db.QueryRow("SELECT COALESCE(MIN(collected_at),'') FROM observations").Scan(&s.EarliestObservation); err != nil {
return nil, err
}
rows, err := k.db.Query("SELECT COALESCE(source_id,'unknown'), COUNT(*) FROM observations GROUP BY source_id")
if err != nil {
return nil, err
}
defer rows.Close()
for rows.Next() {
var src string
var n int
if err := rows.Scan(&src, &n); err != nil {
return nil, err
}
s.BySource[src] = n
}
if err := rows.Err(); err != nil {
return nil, err
}
rows2, err := k.db.Query("SELECT COALESCE(status,'active'), COUNT(*) FROM threads GROUP BY status")
if err != nil {
return nil, err
}
defer rows2.Close()
for rows2.Next() {
var st string
var n int
if err := rows2.Scan(&st, &n); err != nil {
return nil, err
}
s.ThreadsByStatus[st] = n
}
if err := rows2.Err(); err != nil {
return nil, err
}
rows3, err := k.db.Query("SELECT node_id, COUNT(*) FROM observations WHERE node_id<>'' GROUP BY node_id")
if err != nil {
return nil, err
}
defer rows3.Close()
for rows3.Next() {
var nid string
var n int
if err := rows3.Scan(&nid, &n); err != nil {
return nil, err
}
s.ByOriginNode[nid] = n
}
if err := rows3.Err(); err != nil {
return nil, err
}
if s.KnowledgeVector, err = k.KnowledgeVector(); err != nil {
return nil, err
}
return s, nil
}