feat(raft): expose raft metrics on /metrics and /health
CI / test (push) Has been cancelled
CI / verify (push) Has been cancelled
Clients CI / build-server (push) Has been cancelled
Clients CI / test-python (push) Has been cancelled
Clients CI / test-javascript (push) Has been cancelled
Clients CI / test-nim (push) Has been cancelled
Clients CI / test-rust (push) Has been cancelled

- RaftMetrics counters: elections, term changes, appends, commit waits/ms,
  timeouts, lost leadership, forwards, applies, compactions
- Gauges via prometheusText: is_leader, term, log size, commit/applied,
  apply lag, snapshot index
- Wire httpServer.raftNode; extend GET /metrics and GET /health
This commit is contained in:
2026-07-30 21:38:44 +03:00
parent 53704e1036
commit 1b3c26123a
7 changed files with 183 additions and 8 deletions
+33 -4
View File
@@ -24,6 +24,7 @@ import ../protocol/auth
import ../protocol/ratelimit
import ../core/registry
import ../core/backup
import ../core/raft
type
HttpServer* = ref object
@@ -37,6 +38,8 @@ type
authManager*: AuthManager
rateLimiter*: RateLimiter
ws*: WsServer
## Optional live raft node for /metrics and /health (set from main).
raftNode*: RaftNode
Metrics* = ref object
queriesTotal*: int
@@ -254,21 +257,47 @@ proc queryHandler(server: HttpServer): RequestHandler =
server.metrics.queryErrors += 1
ctx.json(%*{"error": errMsg}, 400)
proc healthHandler(): RequestHandler =
proc healthHandler(server: HttpServer): RequestHandler =
return proc(request: Request) {.gcsafe.} =
let ctx = newContext(request)
ctx.json(%*{"status": "ok", "version": "1.1.6"})
var body = %*{
"status": "ok",
"version": "1.1.6"
}
if server.raftNode != nil:
let n = server.raftNode
let role = case n.state
of rsLeader: "leader"
of rsCandidate: "candidate"
of rsFollower: "follower"
body["raft"] = %*{
"enabled": true,
"node_id": n.id,
"role": role,
"term": n.currentTerm,
"leader_id": n.leaderId,
"commit_index": n.commitIndex,
"last_applied": n.lastApplied,
"apply_lag": n.applyLag,
"log_entries": n.log.len,
"snapshot_index": n.lastSnapshotIndex
}
else:
body["raft"] = %*{"enabled": false}
ctx.json(body)
proc metricsHandler(server: HttpServer): RequestHandler =
return proc(request: Request) {.gcsafe.} =
let ctx = newContext(request)
if not server.checkAuth(request, ctx):
return
let prometheus = "baradb_queries_total " & $server.metrics.queriesTotal & "\n" &
var prometheus = "baradb_queries_total " & $server.metrics.queriesTotal & "\n" &
"baradb_query_errors_total " & $server.metrics.queryErrors & "\n" &
"baradb_inserts_total " & $server.metrics.insertCount & "\n" &
"baradb_selects_total " & $server.metrics.selectCount & "\n" &
"baradb_connections_active " & $server.metrics.activeConnections & "\n"
if server.raftNode != nil:
prometheus.add(server.raftNode.prometheusText())
request.respond(200, @[("Content-Type", "text/plain; charset=utf-8")], prometheus)
proc authHandler(server: HttpServer): RequestHandler =
@@ -886,7 +915,7 @@ proc run*(server: HttpServer, port: int = 9470) =
router.get("/admin", server.adminHandler())
router.get("/", server.adminHandler())
router.post("/query", server.queryHandler())
router.get("/health", healthHandler())
router.get("/health", server.healthHandler())
router.get("/metrics", server.metricsHandler())
router.post("/auth", server.authHandler())
router.post("/auth/scram/start", server.scramStartHandler())