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}