code wiki / _hdl_build / nx_metrics.nx

nx_metrics.nx source

↩ module page · 122 lines · 5510 B

1// nx_metrics.nx -- CLI over the sovereign metrics ring (nx_metrics_ring). Query daemon health HISTORY + 2// uptime SLO from the bounded binary TSDB. `put` injects a sample (used by the gate for deterministic 3// proof; the live writer is nx_metrics_sampler). nx_heal forks this for its MCP uptime/history verbs. 4// nx_metrics uptime <ring> <name> <window_sec> -> "<name> uptime <permille>/1000 over <w>s (n=<samples>)" 5// nx_metrics history <ring> <name> [n] -> recent samples: <ts> <verdict> fails=<f> 6// nx_metrics count <ring> -> total records stored 7// nx_metrics put <ring> <name> <verdict> <fails> <ts>-> append one sample (deterministic) 8// license_tier: ORIGINAL module: nishi-core.ops.metrics_cli 9import "nx_syscalls.nx" 10import "nx_metrics_ring.nx" 11 12func mc_p(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } sys_write(1, s, n); return 0 } 13func mc_pn(v: i64) -> i64 { 14 let b: *u8 = sys_mmap(28) 15 var m: i64 = v 16 if m < 0 { sys_write(1, "-" as *u8, 1); m = 0 - m } 17 let t: *u8 = sys_mmap(28); var k: i64 = 0 18 if m == 0 { t[0] = 48 as u8; k = 1 } 19 while m > 0 { t[k] = (48 + (m % 10)) as u8; m = m / 10; k = k + 1 } 20 var i: i64 = 0; while i < k { b[i] = t[k - 1 - i]; i = i + 1 } 21 sys_write(1, b, k); return 0 22} 23func mc_streq(a: *u8, b: *u8) -> i64 { 24 var i: i64 = 0 25 while a[i] != (0 as u8) { if a[i] != b[i] { return 0 } i = i + 1 } 26 if b[i] != (0 as u8) { return 0 } 27 return 1 28} 29func mc_atoi(s: *u8) -> i64 { 30 var v: i64 = 0; var i: i64 = 0; var go: i64 = 1 31 while go == 1 { let c: i64 = s[i] as i64; if c < 48 { go = 0 } else { if c > 57 { go = 0 } else { v = v * 10 + (c - 48); i = i + 1 } } } 32 return v 33} 34func mc_vname(v: i64) -> *u8 { 35 if v == MR_V_SERVING { return "SERVING" as *u8 } 36 if v == MR_V_REFUSED { return "REFUSED" as *u8 } 37 if v == MR_V_HUNG { return "HUNG" as *u8 } 38 return "BADRESP" as *u8 39} 40 41func main(argc: i64, argv: *i64) -> i64 { 42 if argc < 3 { mc_p("usage: nx_metrics uptime|history|count|put <ring> ...\n" as *u8); return 2 } 43 let verb: *u8 = argv[1] as *u8 44 let ring: *u8 = argv[2] as *u8 45 46 if mc_streq(verb, "put" as *u8) == 1 { 47 if argc < 7 { mc_p("usage: nx_metrics put <ring> <name> <verdict> <fails> <ts>\n" as *u8); return 2 } 48 let h: i64 = mr_hash(argv[3] as *u8) 49 let rc: i64 = mr_append(ring, mc_atoi(argv[6] as *u8), h, mc_atoi(argv[4] as *u8), mc_atoi(argv[5] as *u8)) 50 if rc != 0 { mc_p("put: append failed\n" as *u8); return 1 } 51 return 0 52 } 53 if mc_streq(verb, "count" as *u8) == 1 { 54 let fd: i64 = sys_openat_rd(ring) 55 if fd < 0 { mc_p("0\n" as *u8); return 0 } 56 let hdr: *u8 = sys_mmap(64) 57 mc_pn(mr_count(fd, hdr)); mc_p("\n" as *u8) 58 sys_close(fd) 59 return 0 60 } 61 if mc_streq(verb, "uptime" as *u8) == 1 { 62 if argc < 5 { mc_p("usage: nx_metrics uptime <ring> <name> <window_sec>\n" as *u8); return 2 } 63 let name: *u8 = argv[3] as *u8 64 let win: i64 = mc_atoi(argv[4] as *u8) 65 let now: i64 = sys_now_realtime_sec() 66 let h: i64 = mr_hash(name) 67 // count samples in window for the report 68 let fd: i64 = sys_openat_rd(ring) 69 var n: i64 = 0 70 if fd >= 0 { 71 let hdr: *u8 = sys_mmap(64) 72 let cnt: i64 = mr_count(fd, hdr) 73 let rec: *u8 = sys_mmap(32) 74 var i: i64 = 0 75 while i < cnt { 76 if mr_pread(fd, 64 + i * 32, rec, 32) == 32 { if mr_geti(rec, 8) == h { let ts: i64 = mr_geti(rec, 0); if ts >= now - win { if ts <= now { n = n + 1 } } } } 77 i = i + 1 78 } 79 sys_close(fd) 80 } 81 let up: i64 = mr_uptime(ring, h, win, now) 82 mc_p(name); mc_p(" uptime " as *u8) 83 if up < 0 { mc_p("NO-DATA" as *u8) } else { mc_pn(up); mc_p("/1000" as *u8) } 84 mc_p(" over " as *u8); mc_pn(win); mc_p("s (n=" as *u8); mc_pn(n); mc_p(" samples)\n" as *u8) 85 if up < 0 { return 1 } 86 return 0 87 } 88 if mc_streq(verb, "history" as *u8) == 1 { 89 if argc < 4 { mc_p("usage: nx_metrics history <ring> <name> [n]\n" as *u8); return 2 } 90 let name: *u8 = argv[3] as *u8 91 var want: i64 = 20 92 if argc >= 5 { want = mc_atoi(argv[4] as *u8) } 93 let h: i64 = mr_hash(name) 94 let fd: i64 = sys_openat_rd(ring) 95 if fd < 0 { mc_p("(no ring)\n" as *u8); return 1 } 96 let hdr: *u8 = sys_mmap(64) 97 let cnt: i64 = mr_count(fd, hdr) 98 let rec: *u8 = sys_mmap(32) 99 // walk newest-first: find matching indices from the end 100 var shown: i64 = 0 101 var i: i64 = cnt - 1 102 mc_p(name); mc_p(" history (newest first):\n" as *u8) 103 while i >= 0 { 104 if shown >= want { i = 0 - 1 } 105 else { 106 if mr_pread(fd, 64 + i * 32, rec, 32) == 32 { if mr_geti(rec, 8) == h { 107 mc_p(" ts=" as *u8); mc_pn(mr_geti(rec, 0)) 108 mc_p(" " as *u8); mc_p(mc_vname(mr_geti(rec, 16))) 109 mc_p(" fails=" as *u8); mc_pn(mr_geti(rec, 24)) 110 mc_p("\n" as *u8) 111 shown = shown + 1 112 } } 113 i = i - 1 114 } 115 } 116 sys_close(fd) 117 if shown == 0 { mc_p(" (no samples for this name)\n" as *u8) } 118 return 0 119 } 120 mc_p("usage: nx_metrics uptime|history|count|put <ring> ...\n" as *u8) 121 return 2 122}