876d2aa45f
Refs #2 - /metrics served on a dedicated port (KNOX_METRICS_ADDR, default localhost:8932) via prometheus/client_golang, with Go runtime + process collectors - DB-derived gauges refreshed per scrape: observations by source, last-24h observations, entries, projects, sessions, pending reflections, threads by status, peers, observations by origin node, knowledge vector (max hcl per node) - live gossip counters (pulls/pushes, observations pulled/pushed, errors) incremented during the anti-entropy sweep; Run accepts an optional metrics handle (nil for one-shot CLI) - knox_node_info{node_id,name} for scrape identification - internal/metrics package + db MetricsSnapshot; tests for snapshot, scrape output, and counter increments
108 lines
3.0 KiB
Go
108 lines
3.0 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
|
|
} |