code wiki / _hdl_build / nx_apm_dashboard.nx
nx_apm_dashboard.nx source
↩ module page · 228 lines · 13402 B
1// nx_apm_dashboard.nx -- SOVEREIGN "New-Relic-style" status board: renders the APM time-series
2// (knowledge/status/apm_collect.tsv, written by nx_apm_collect) into a self-contained HTML page.
3//
4// TTFB-honest by construction: the verdict is recomputed from the row's stats (downs/timeouts/stalls),
5// and `slowclose` (keep-alive/idle-hold = fast first byte, slow close) is shown as an INFO badge, NEVER
6// as a failure -- so the board never reproduces the read-until-close "20s wedge" artifact. Zero 3rd-party
7// JS/CDN (sovereignty invariant): inline CSS only. Groups rows by daemon label, latest sample wins,
8// renders a colour-coded card grid + an incidents list.
9//
10// in: knowledge/status/apm_collect.tsv (argv[1] overrides)
11// out: knowledge/status/apm_dashboard.html (argv[2] overrides)
12// TSV cols: epoch(0) label(1) port(2) path(3) conc(4) oks(5) nres(6) min(7) p50(8) p95(9) max(10)
13// stalls(11) timeouts(12) downs(13) maxtotal(14) slowclose(15)
14// license_tier: ORIGINAL
15import "nx_syscalls.nx"
16const AD_MAGIC_65536: i64 = 65536
17const AD_MAGIC_4096: i64 = 4096
18const AD_MAGIC_262144: i64 = 262144
19
20const AD_TSV: *u8 = "knowledge/status/apm_collect.tsv"
21const AD_HTML: *u8 = "knowledge/status/apm_dashboard.html"
22const AD_MAX_LABELS: i64 = 64
23const AD_LBL_W: i64 = 40 // bytes per stored label
24
25// verdict codes (recomputed from the row -- ttfb-honest)
26const AD_GREEN: i64 = 0
27const AD_AMBER: i64 = 1
28const AD_RED: i64 = 2
29const AD_DOWN: i64 = 3
30
31func ad_slen(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } return n }
32func ad_w(s: *u8) -> i64 { return sys_write(1, s, ad_slen(s)) }
33func ad_wn(v: i64) -> i64 {
34 let t: *u8 = sys_mmap(24); var m: i64 = v; var k: i64 = 0
35 if m == 0 { t[0] = 48 as u8; k = 1 }
36 while m > 0 { t[k] = (48 + (m - (m/10)*10)) as u8; m = m/10; k = k + 1 }
37 let o: *u8 = sys_mmap(24); var i: i64 = 0; while i < k { o[i] = t[k-1-i]; i = i + 1 }
38 return sys_write(1, o, k)
39}
40func ad_atoi(s: *u8) -> i64 { var v: i64 = 0; var i: i64 = 0; while s[i] != (0 as u8) { let c: i64 = s[i] as i64; if c >= 48 { if c <= 57 { v = v*10 + (c-48) } } i = i + 1 } return v }
41func ad_streq(a: *u8, b: *u8) -> i64 { var i: i64 = 0; while a[i] != (0 as u8) { if a[i] != b[i] { return 0 } i = i + 1 } if b[i] != (0 as u8) { return 0 } return 1 }
42
43// bounded file read (NOT sys_read_file -- that mmaps 4 GiB/call)
44func ad_read_small(path: *u8, buf: *u8, cap: i64) -> i64 {
45 let fd: i64 = sys_openat_rd(path)
46 if fd < 0 { return 0 - 1 }
47 var off: i64 = 0; var go: i64 = 1
48 while go == 1 { if off >= cap { go = 0 } else { let r: i64 = sys_read(fd, buf + off, cap - off); if r <= 0 { go = 0 } else { off = off + r } } }
49 sys_close(fd); return off
50}
51// copy one tab/newline-delimited field; stop[0]=0 tab,1 newline,2 eof; returns next pos.
52func ad_field(buf: *u8, n: i64, pos: i64, out: *u8, outcap: i64, stop: *i64) -> i64 {
53 var i: i64 = pos; var w: i64 = 0; var done: i64 = 0
54 while done == 0 {
55 if i >= n { stop[0] = 2; done = 1 }
56 else { let c: i64 = buf[i] as i64
57 if c == 9 { stop[0] = 0; i = i + 1; done = 1 }
58 else { if c == 10 { stop[0] = 1; i = i + 1; done = 1 }
59 else { if w < outcap - 1 { out[w] = buf[i]; w = w + 1 } i = i + 1 } } }
60 }
61 out[w] = 0 as u8; return i
62}
63
64// append C-string into html buf at off, return new off
65func ad_bs(buf: *u8, off: i64, s: *u8) -> i64 { var o: i64 = off; var i: i64 = 0; while s[i] != (0 as u8) { buf[o] = s[i]; o = o + 1; i = i + 1 } return o }
66// append decimal into html buf at off, return new off
67func ad_bn(buf: *u8, off: i64, v: i64) -> i64 {
68 var o: i64 = off; var m: i64 = v
69 if m < 0 { buf[o] = 45 as u8; o = o + 1; m = 0 - m }
70 let t: *u8 = sys_mmap(24); var k: i64 = 0
71 if m == 0 { t[0] = 48 as u8; k = 1 }
72 while m > 0 { t[k] = (48 + (m - (m/10)*10)) as u8; m = m/10; k = k + 1 }
73 var i: i64 = 0; while i < k { buf[o + i] = t[k - 1 - i]; i = i + 1 }
74 return o + k
75}
76
77// verdict from a row's stats (ttfb-honest: slowclose is NOT a factor)
78func ad_verdict(conc: i64, oks: i64, stalls: i64, timeouts: i64, downs: i64) -> i64 {
79 if conc > 0 { if downs >= conc { return AD_DOWN } }
80 if timeouts > 0 { return AD_RED }
81 if downs > 0 { return AD_RED }
82 if stalls > 0 { return AD_AMBER }
83 return AD_GREEN
84}
85func ad_vname(v: i64) -> *u8 {
86 if v == AD_GREEN { return "GREEN" as *u8 }
87 if v == AD_AMBER { return "AMBER" as *u8 }
88 if v == AD_RED { return "RED" as *u8 }
89 return "DOWN" as *u8
90}
91func ad_vcolor(v: i64) -> *u8 {
92 if v == AD_GREEN { return "#1a7f37" as *u8 }
93 if v == AD_AMBER { return "#bf8700" as *u8 }
94 if v == AD_RED { return "#cf222e" as *u8 }
95 return "#6e7781" as *u8
96}
97
98// find label in store, or add it; returns index (or -1 if full)
99func ad_find_or_add(store: *u8, np: *i64, name: *u8) -> i64 {
100 var i: i64 = 0
101 while i < np[0] { if ad_streq(store + i*AD_LBL_W, name) == 1 { return i } i = i + 1 }
102 if np[0] >= AD_MAX_LABELS { return 0 - 1 }
103 let idx: i64 = np[0]
104 let dst: *u8 = store + idx*AD_LBL_W
105 var w: i64 = 0; while name[w] != (0 as u8) { if w < AD_LBL_W - 1 { dst[w] = name[w] } w = w + 1 }
106 dst[w] = 0 as u8
107 np[0] = idx + 1
108 return idx
109}
110
111// seg-store key:value helpers (NO tsv): find "key=<int>" on its own line -> the int.
112func ad_starts(buf: *u8, ls: i64, end: i64, key: *u8) -> i64 {
113 var m: i64 = 0
114 while key[m] != (0 as u8) { if ls+m >= end { return 0 } if buf[ls+m] != key[m] { return 0 } m = m + 1 }
115 return m
116}
117func ad_kv(buf: *u8, n: i64, key: *u8) -> i64 {
118 var ls: i64 = 0; var i: i64 = 0
119 while i <= n {
120 var nl: i64 = 0; if i >= n { nl = 1 } else { if buf[i] == (10 as u8) { nl = 1 } }
121 if nl == 1 {
122 let kl: i64 = ad_starts(buf, ls, i, key)
123 if kl > 0 { var v: i64 = 0; var p: i64 = ls + kl; while p < i { let c: i64 = buf[p] as i64; if c >= 48 { if c <= 57 { v = v*10 + (c-48) } } p = p + 1 } return v }
124 ls = i + 1
125 }
126 i = i + 1
127 }
128 return 0
129}
130
131func main(argc: i64, argv: *i64) -> i64 {
132 var storedir: *u8 = "knowledge/store" as *u8; if argc >= 2 { storedir = argv[1] as *u8 }
133 var html: *u8 = AD_HTML; if argc >= 3 { html = argv[2] as *u8 }
134
135 // per-label latest stats (parallel arrays)
136 let store: *u8 = sys_mmap(AD_MAX_LABELS * AD_LBL_W)
137 let np: *i64 = sys_mmap(8) as *i64; np[0] = 0
138 let s_port: *i64 = sys_mmap(AD_MAX_LABELS*8) as *i64
139 let s_conc: *i64 = sys_mmap(AD_MAX_LABELS*8) as *i64
140 let s_oks: *i64 = sys_mmap(AD_MAX_LABELS*8) as *i64
141 let s_p50: *i64 = sys_mmap(AD_MAX_LABELS*8) as *i64
142 let s_max: *i64 = sys_mmap(AD_MAX_LABELS*8) as *i64
143 let s_stall:*i64 = sys_mmap(AD_MAX_LABELS*8) as *i64
144 let s_to: *i64 = sys_mmap(AD_MAX_LABELS*8) as *i64
145 let s_down: *i64 = sys_mmap(AD_MAX_LABELS*8) as *i64
146 let s_slow: *i64 = sys_mmap(AD_MAX_LABELS*8) as *i64
147 let s_epoch:*i64 = sys_mmap(AD_MAX_LABELS*8) as *i64
148 let s_samp: *i64 = sys_mmap(AD_MAX_LABELS*8) as *i64
149 var rows: i64 = 0
150
151 // read the SOVEREIGN seg-store (NO tsv): apm-ids index -> per-label key:value records
152 let idxp: *u8 = sys_mmap(512); var ipo: i64 = ad_bs(idxp, 0, storedir); idxp[ipo]=47 as u8; ipo=ipo+1; ipo=ad_bs(idxp, ipo, "apm-ids" as *u8); idxp[ipo]=0 as u8
153 let idxb: *u8 = sys_mmap(AD_MAGIC_65536); let idn: i64 = ad_read_small(idxp, idxb, AD_MAGIC_65536)
154 if idn <= 0 { ad_w("nx_apm_dashboard: no seg-store data at " as *u8); ad_w(idxp); ad_w("\n" as *u8); return 1 }
155 let lbl: *u8 = sys_mmap(64); let recp: *u8 = sys_mmap(512); let rec: *u8 = sys_mmap(AD_MAGIC_4096)
156 var ls: i64 = 0; var i: i64 = 0
157 while i <= idn {
158 var nl: i64 = 0; if i >= idn { nl = 1 } else { if idxb[i] == (10 as u8) { nl = 1 } }
159 if nl == 1 {
160 if i > ls {
161 var w: i64 = 0; var k: i64 = ls; while k < i { if w < 63 { lbl[w] = idxb[k]; w = w + 1 } k = k + 1 } lbl[w] = 0 as u8
162 var po: i64 = ad_bs(recp, 0, storedir); recp[po]=47 as u8; po=po+1; po=ad_bs(recp, po, "apm-" as *u8); po = ad_bs(recp, po, lbl); recp[po] = 0 as u8
163 let rn: i64 = ad_read_small(recp, rec, AD_MAGIC_4096)
164 if rn > 0 {
165 let idx: i64 = ad_find_or_add(store, np, lbl)
166 if idx >= 0 {
167 s_port[idx]=ad_kv(rec,rn,"port=" as *u8); s_conc[idx]=ad_kv(rec,rn,"conc=" as *u8); s_oks[idx]=ad_kv(rec,rn,"oks=" as *u8)
168 s_p50[idx]=ad_kv(rec,rn,"ttfb_p50=" as *u8); s_max[idx]=ad_kv(rec,rn,"ttfb_max=" as *u8)
169 s_stall[idx]=ad_kv(rec,rn,"stalls=" as *u8); s_to[idx]=ad_kv(rec,rn,"timeouts=" as *u8); s_down[idx]=ad_kv(rec,rn,"downs=" as *u8)
170 s_slow[idx]=ad_kv(rec,rn,"slowclose=" as *u8); s_epoch[idx]=ad_kv(rec,rn,"epoch=" as *u8); s_samp[idx]=1; rows=rows+1
171 }
172 }
173 }
174 ls = i + 1
175 }
176 i = i + 1
177 }
178
179 // ---- emit HTML ----
180 let hb: *u8 = sys_mmap(AD_MAGIC_262144); var o: i64 = 0
181 o = ad_bs(hb, o, "<!doctype html><html><head><meta charset=utf-8><meta name=viewport content='width=device-width,initial-scale=1'><title>Nishi APM</title><style>" as *u8)
182 o = ad_bs(hb, o, "body{background:#0d1117;color:#e6edf3;font:14px system-ui,sans-serif;margin:0;padding:24px}h1{font-size:20px;margin:0 0 4px}.sub{color:#8b949e;font-size:12px;margin-bottom:18px}" as *u8)
183 o = ad_bs(hb, o, ".grid{display:flex;flex-wrap:wrap;gap:12px}.card{background:#161b22;border:1px solid #30363d;border-left-width:5px;border-radius:8px;padding:12px 14px;min-width:190px}" as *u8)
184 o = ad_bs(hb, o, ".nm{font-weight:600;font-size:15px}.pt{color:#8b949e;font-size:12px}.v{font-weight:700;float:right}.lat{font-size:22px;margin:6px 0 2px}.mut{color:#8b949e;font-size:12px}.badge{display:inline-block;background:#1f2937;color:#9da7b3;border-radius:4px;padding:1px 6px;font-size:11px;margin-top:6px}" as *u8)
185 o = ad_bs(hb, o, ".inc{margin-top:22px}.inc h2{font-size:15px}.ok{color:#1a7f37}</style></head><body>" as *u8)
186 o = ad_bs(hb, o, "<h1>Nishi APM — daemon health</h1><div class=sub>latency = time-to-first-byte (TTFB); slowclose = keep-alive idle-hold (informational, not a wedge). " as *u8)
187 o = ad_bn(hb, o, np[0]); o = ad_bs(hb, o, " daemons, " as *u8); o = ad_bn(hb, o, rows); o = ad_bs(hb, o, " samples.</div><div class=grid>" as *u8)
188
189 var k: i64 = 0; var nbad: i64 = 0
190 while k < np[0] {
191 let v: i64 = ad_verdict(s_conc[k], s_oks[k], s_stall[k], s_to[k], s_down[k])
192 if v != AD_GREEN { nbad = nbad + 1 }
193 o = ad_bs(hb, o, "<div class=card style='border-left-color:" as *u8); o = ad_bs(hb, o, ad_vcolor(v)); o = ad_bs(hb, o, "'>" as *u8)
194 o = ad_bs(hb, o, "<span class=v style='color:" as *u8); o = ad_bs(hb, o, ad_vcolor(v)); o = ad_bs(hb, o, "'>" as *u8); o = ad_bs(hb, o, ad_vname(v)); o = ad_bs(hb, o, "</span>" as *u8)
195 o = ad_bs(hb, o, "<div class=nm>" as *u8); o = ad_bs(hb, o, store + k*AD_LBL_W); o = ad_bs(hb, o, "</div><div class=pt>:" as *u8); o = ad_bn(hb, o, s_port[k]); o = ad_bs(hb, o, "</div>" as *u8)
196 o = ad_bs(hb, o, "<div class=lat>" as *u8); o = ad_bn(hb, o, s_p50[k]); o = ad_bs(hb, o, "<span class=mut> ms p50</span></div>" as *u8)
197 o = ad_bs(hb, o, "<div class=mut>max " as *u8); o = ad_bn(hb, o, s_max[k]); o = ad_bs(hb, o, "ms · ok " as *u8); o = ad_bn(hb, o, s_oks[k]); o = ad_bs(hb, o, "/" as *u8); o = ad_bn(hb, o, s_conc[k]); o = ad_bs(hb, o, "</div>" as *u8)
198 if s_slow[k] > 0 { o = ad_bs(hb, o, "<div class=badge>slowclose " as *u8); o = ad_bn(hb, o, s_slow[k]); o = ad_bs(hb, o, " (keep-alive)</div>" as *u8) }
199 o = ad_bs(hb, o, "</div>" as *u8)
200 k = k + 1
201 }
202 o = ad_bs(hb, o, "</div>" as *u8)
203
204 // incidents (non-GREEN)
205 o = ad_bs(hb, o, "<div class=inc><h2>Incidents</h2>" as *u8)
206 if nbad == 0 { o = ad_bs(hb, o, "<div class=ok>All daemons healthy (no stalls, timeouts, or down).</div>" as *u8) }
207 else {
208 o = ad_bs(hb, o, "<ul>" as *u8)
209 var j: i64 = 0
210 while j < np[0] {
211 let v: i64 = ad_verdict(s_conc[j], s_oks[j], s_stall[j], s_to[j], s_down[j])
212 if v != AD_GREEN {
213 o = ad_bs(hb, o, "<li><b>" as *u8); o = ad_bs(hb, o, store + j*AD_LBL_W); o = ad_bs(hb, o, "</b> :" as *u8); o = ad_bn(hb, o, s_port[j])
214 o = ad_bs(hb, o, " — " as *u8); o = ad_bs(hb, o, ad_vname(v))
215 o = ad_bs(hb, o, " (p50 " as *u8); o = ad_bn(hb, o, s_p50[j]); o = ad_bs(hb, o, "ms, stalls " as *u8); o = ad_bn(hb, o, s_stall[j]); o = ad_bs(hb, o, ", timeouts " as *u8); o = ad_bn(hb, o, s_to[j]); o = ad_bs(hb, o, ", down " as *u8); o = ad_bn(hb, o, s_down[j]); o = ad_bs(hb, o, ")</li>" as *u8)
216 }
217 j = j + 1
218 }
219 o = ad_bs(hb, o, "</ul>" as *u8)
220 }
221 o = ad_bs(hb, o, "</div></body></html>" as *u8)
222
223 let fd: i64 = sys_openat_wr(html, 0x1a4)
224 if fd < 0 { ad_w("nx_apm_dashboard: cannot write " as *u8); ad_w(html); ad_w("\n" as *u8); return 1 }
225 sys_write(fd, hb, o); sys_close(fd)
226 ad_w("nx_apm_dashboard: wrote " as *u8); ad_w(html); ad_w(" (" as *u8); ad_wn(np[0]); ad_w(" daemons, " as *u8); ad_wn(rows); ad_w(" samples, " as *u8); ad_wn(nbad); ad_w(" incidents)\n" as *u8)
227 return 0
228}