code wiki / _hdl_build / nx_apm_pulse.nx
nx_apm_pulse.nx source
↩ module page · 65 lines · 3334 B
1// nx_apm_pulse.nx -- SOVEREIGN active-monitoring cadence ("the New-Relic heartbeat"). Each cycle it
2// runs the collector (probe daemons -> append apm_collect.tsv) then the dashboard (regen apm_dashboard.html),
3// prints a heartbeat, and sleeps `interval` seconds. Thin orchestrator over two already-gated organs
4// (nx_apm_collect 5/5, nx_apm_dashboard 5/5) -- it sequences them on a timer; cycles=0 runs forever.
5//
6// usage: nx_apm_pulse [interval_sec=30] [cycles=0(forever)] [ip=127.0.0.1] [collector_elf] [dashboard_elf]
7// ip=127.0.0.1 on the NAS (loopback) OR a.b.c.d to monitor over LAN. Run with CWD=nxc2 so the organs'
8// relative knowledge/status/ paths resolve. license_tier: ORIGINAL
9import "nx_syscalls.nx"
10
11const AP_COLLECT: *u8 = "_offc/nx_apm_collect.elf"
12const AP_DASH: *u8 = "_offc/nx_apm_dashboard.elf"
13
14func ap_slen(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } return n }
15func ap_w(s: *u8) -> i64 { return sys_write(1, s, ap_slen(s)) }
16func ap_wn(v: i64) -> i64 {
17 let t: *u8 = sys_mmap(24); var m: i64 = v; var k: i64 = 0
18 if m == 0 { t[0] = 48 as u8; k = 1 }
19 while m > 0 { t[k] = (48 + (m - (m/10)*10)) as u8; m = m/10; k = k + 1 }
20 let o: *u8 = sys_mmap(24); var i: i64 = 0; while i < k { o[i] = t[k-1-i]; i = i + 1 }
21 return sys_write(1, o, k)
22}
23func ap_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 }
24
25// fork+exec `elf` with optional one string arg; parent waits; returns child exit code.
26func ap_run(elf: *u8, arg1: *u8) -> i64 {
27 let pid: i64 = sys_fork()
28 if pid == 0 {
29 let av: *i64 = sys_mmap(8*3) as *i64
30 av[0] = elf as i64
31 if (arg1 as i64) != 0 { av[1] = arg1 as i64; av[2] = 0 } else { av[1] = 0 }
32 let ev: *i64 = sys_mmap(8) as *i64; ev[0] = 0
33 sys_execve(elf, av, ev); sys_exit(127)
34 }
35 let st: *i64 = sys_mmap(16) as *i64; sys_wait4(pid, st, 0)
36 return (st[0] >> 8) & 0xff
37}
38
39func main(argc: i64, argv: *i64) -> i64 {
40 var interval: i64 = 30
41 var cycles: i64 = 0
42 var ip: *u8 = "127.0.0.1" as *u8
43 var collector: *u8 = AP_COLLECT
44 var dash: *u8 = AP_DASH
45 if argc >= 2 { interval = ap_atoi(argv[1] as *u8) }
46 if argc >= 3 { cycles = ap_atoi(argv[2] as *u8) }
47 if argc >= 4 { ip = argv[3] as *u8 }
48 if argc >= 5 { collector = argv[4] as *u8 }
49 if argc >= 6 { dash = argv[5] as *u8 }
50
51 ap_w("=== NISHI APM PULSE (active cadence) interval=" as *u8); ap_wn(interval); ap_w("s cycles=" as *u8); ap_wn(cycles); ap_w(" ip=" as *u8); ap_w(ip); ap_w(" ===\n" as *u8)
52
53 var c: i64 = 0
54 var run: i64 = 1
55 while run == 1 {
56 let rc1: i64 = ap_run(collector, ip) // probe daemons -> append apm_collect.tsv
57 let rc2: i64 = ap_run(dash, 0 as *u8) // regen apm_dashboard.html
58 c = c + 1
59 ap_w("[apm-pulse] cycle " as *u8); ap_wn(c); ap_w(" done @epoch " as *u8); ap_wn(sys_now_realtime_sec()); ap_w(" (collect rc=" as *u8); ap_wn(rc1); ap_w(", dash rc=" as *u8); ap_wn(rc2); ap_w(")\n" as *u8)
60 if cycles > 0 { if c >= cycles { run = 0 } }
61 if run == 1 { sys_sleep_ms(interval * 1000) }
62 }
63 ap_w("[apm-pulse] done (" as *u8); ap_wn(c); ap_w(" cycles)\n" as *u8)
64 return 0
65}