nx_telemetry_bus.nx
buildroot/runtime/nx_telemetry_bus.nx
about
nx_telemetry.nx -- substrate telemetry bus.
Sealed-enum-typed event bus for substrate-internal observability.
Closes the OBD predictive-maintenance pipeline loop (commit
87dca0a0): consumer emits anomaly verdicts -> telemetry bus ->
pluggable sink (stdout JSON V1; future MQTT shim / syslog / file
when those sinks land).
Per INTEROPERABILITY_CHARTER.md the same telemetry bus consumes
events from EVERY protocol shim's diag_fn + EVERY substrate-side
consumer + the silicon-feedback hot-report. One uniform format
across the whole substrate.
Status: SEED v0.1.0. 2026-05-27.
WINNER-TIER: WINNER-A CANDIDATE
INCUMBENTS: syslog (RFC 5424), Prometheus client libs,
OpenTelemetry (OTLP), structlog (Python), statsd
protocol, Vector.dev event router
NUMBERS: V1 ships the bus + stdout-JSON sink; throughput
measurement vs structlog/Prometheus pending paired
bench
GAP: vs OpenTelemetry the gap is feature coverage (no
distributed-trace context yet); vs syslog the gap is
transport (V1 is in-process; future MQTT/syslog
sinks close it); vs structlog Nishi WINS on
sealed-enum typing (structlog is string-keyed and
loses type safety)
PLAN: M-next: paired bench vs structlog on 1M-event burst;
re-rate; add distributed-trace context for
OpenTelemetry parity
EXEMPTION REASON: n/a; provisional pending measurement
V1 SCOPE:
- 8 sealed event kinds (covers anomaly / perf / health /
shim_diag / silicon_feedback / substrate_panic / user / debug)
- 4 sealed severity levels (INFO / WARN / ERROR / CRITICAL)
- NxTelemetryEvent struct (kind / severity / source-string /
ts_ns / 3 value fields for structured numeric payload)
- Pluggable NxTelemetrySink (caller-supplied emit function)
dependencies 1 imports · 0 importers
imports: nx_syscalls.nx
imported by: nobody (leaf or entry point)
structs
| 137 | struct NxTelemetryEvent |
| 156 | struct NxTelemetrySink |
| 286 | struct NxTelemetryRateLimiter |
| 434 | struct NxTelemetryBus |
consts
| 60 | const NX_TM_OK: i64 = 0 |
| 61 | const NX_TM_BAD_KIND: i64 = 1 // event kind out of sealed enum |
| 62 | const NX_TM_BAD_SEVERITY: i64 = 2 |
| 63 | const NX_TM_RATE_LIMITED: i64 = 3 // token bucket exhausted |
| 64 | const NX_TM_SINK_FAULT: i64 = 4 // configured sink fn returned non-OK |
| 65 | const NX_TM_BAD_SINK_KIND: i64 = 5 // sink kind out of sealed enum |
| 66 | const NX_TM_FANOUT_OVERFLOW: i64 = 6 // fanout array exceeds NX_TM_FANOUT_MAX |
| 75 | const NX_TM_SINK_KIND_STDOUT_JSON: i64 = 0 // V1; built-in NDJSON sink |
| 76 | const NX_TM_SINK_KIND_NULL: i64 = 1 // no-op (test/silence) |
| 77 | const NX_TM_SINK_KIND_FANOUT: i64 = 2 // dispatches to N sub-sinks |
| 78 | const NX_TM_SINK_KIND_BUFFER: i64 = 3 // accumulates events for operator drain |
| 83 | const NX_TM_SINK_KIND_N: i64 = 4 |
| 93 | const NX_TM_FANOUT_MAX: i64 = 8 |
| 101 | const NX_TM_KIND_ANOMALY: i64 = 0 // pred-maint anomaly verdict |
| 102 | const NX_TM_KIND_PERF_SAMPLE: i64 = 1 // bench / silicon-feedback per-PC sample |
| 103 | const NX_TM_KIND_HEALTH: i64 = 2 // substrate process / kernel health metric |
| 104 | const NX_TM_KIND_SHIM_DIAG: i64 = 3 // protocol shim diag_fn output |
| 105 | const NX_TM_KIND_SILICON_FB: i64 = 4 // hot-report / multi-tier ROI verdict |
| 106 | const NX_TM_KIND_PANIC: i64 = 5 // substrate panic / unrecoverable verdict |
| 107 | const NX_TM_KIND_USER: i64 = 6 // operator-emitted (debug / annotation) |
| 108 | const NX_TM_KIND_DEBUG: i64 = 7 // dev-only; suppressed in production builds |
| 109 | const NX_TM_KIND_N: i64 = 8 |
| 118 | const NX_TM_SEV_INFO: i64 = 0 |
| 119 | const NX_TM_SEV_WARN: i64 = 1 |
| 120 | const NX_TM_SEV_ERROR: i64 = 2 |
| 121 | const NX_TM_SEV_CRITICAL: i64 = 3 |
| 122 | const NX_TM_SEV_N: i64 = 4 |
| 284 | const NX_TM_RL_SLOTS: i64 = 64 |
| 543 | const NX_TM_SOURCE_PRED_MAINT: *u8 = "nx_pred_maint_consumer" as *u8 |
| 544 | const NX_TM_SOURCE_PRED_MAINT_LEN: i64 = 22 |
functions
| 85 | func nx_tm_sink_kind_is_valid(k: i64) -> i64 called by 1: nx_tm_dispatch_to_sink |
| 111 | func nx_tm_kind_is_valid(k: i64) -> i64 called by 1: nx_tm_emit |
| 124 | func nx_tm_sev_is_valid(s: i64) -> i64 called by 1: nx_tm_emit |
| 177 | func nx_tm_sink_init_stdout_json(sink: *NxTelemetrySink, rate_cap: i64) -> i64 |
| 191 | func nx_tm_sink_init_null(sink: *NxTelemetrySink) -> i64 |
| 205 | func nx_tm_sink_init_fanout(sink: *NxTelemetrySink, |
| 222 | func nx_tm_sink_init_buffer(sink: *NxTelemetrySink, |
| 246 | func nx_tm_sink_buffer_drain(sink: *NxTelemetrySink, |
| 295 | func nx_tm_hash_source(src: *u8, len: i64) -> i64 called by 1: nx_tm_rl_try_consume |
| 306 | func nx_tm_rl_init(rl: *NxTelemetryRateLimiter, called by 1: main |
| 327 | func nx_tm_rl_try_consume(rl: *NxTelemetryRateLimiter, |
| 364 | func nx_tm_emit_int(out_buf: *u8, out_off: i64, value: i64) -> i64 |
| 394 | func nx_tm_emit_str(out_buf: *u8, out_off: i64, src: *u8, src_len: i64) -> i64 called by 1: nx_tm_sink_stdout_json |
| 405 | func nx_tm_sink_stdout_json(event: *NxTelemetryEvent) -> i64 |
| 442 | func nx_tm_bus_init(bus: *NxTelemetryBus, called by 1: main |
| 459 | func nx_tm_dispatch_to_sink(sink: *NxTelemetrySink, |
| 509 | func nx_tm_emit(bus: *NxTelemetryBus, event: *NxTelemetryEvent) -> i64 |
| 546 | func nx_tm_emit_anomaly(bus: *NxTelemetryBus, pid: i64, anom_kind: i64, |